diff --git a/.env b/.env
index 5bfeba1..494210b 100644
--- a/.env
+++ b/.env
@@ -2,7 +2,7 @@ Secret_Key = 9f2a1b8c4d6e7f0123456789abcdef01
MYSQL_HOST=127.0.0.1
MYSQL_USER=root
-MYSQL_PASSWORD=root
+MYSQL_PASSWORD=admin
MYSQL_DB=test
DEFAULT_USERNAME=admin
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0a38b02
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+venv/
+*.pyc
+__pycache__/
+.uploads
+static/download/
+downloads/
+uploads/
+
+
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..11a5d8e
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+main.py
\ No newline at end of file
diff --git a/.idea/ManagementApplicationt.iml b/.idea/ManagementApplicationt.iml
new file mode 100644
index 0000000..b6731d8
--- /dev/null
+++ b/.idea/ManagementApplicationt.iml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..a310890
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..a851b58
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index e69de29..52a42d7 100644
--- a/README.md
+++ b/README.md
@@ -0,0 +1 @@
+# MA07-05-2025
diff --git a/activity.log b/activity.log
index c5d6a02..80b7442 100644
--- a/activity.log
+++ b/activity.log
@@ -7713,277 +7713,155 @@ Timestamp: 2026-03-21 18:31:17 | User: Unknown | Action: Search Contractor | Det
Timestamp: 2026-03-21 18:31:17 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-03-21 18:31:17 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-03-21 18:31:20 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 12:25:56 | User: Unknown | Action: Add Subcontractor | Details:
-Timestamp: 2026-03-22 12:27:17 | User: Unknown | Action: Edit Subcontractor | Details:
-Timestamp: 2026-03-22 12:27:31 | User: Unknown | Action: Add Subcontractor | Details:
-Timestamp: 2026-03-22 12:27:39 | User: Unknown | Action: Edit Subcontractor | Details:
-Timestamp: 2026-03-22 12:32:18 | User: Unknown | Action: Edit Subcontractor | Details:
-Timestamp: 2026-03-22 12:33:19 | User: Unknown | Action: Add Subcontractor | Details:
-Timestamp: 2026-03-22 12:33:40 | User: Unknown | Action: Edit Subcontractor | Details:
-Timestamp: 2026-03-22 12:40:57 | User: Unknown | Action: Check State | Details:
-Timestamp: 2026-03-22 12:40:58 | User: Unknown | Action: Add State | Details:
-Timestamp: 2026-03-22 12:42:22 | User: Unknown | Action: Check State | Details:
-Timestamp: 2026-03-22 12:42:23 | User: Unknown | Action: Add State | Details:
-Timestamp: 2026-03-22 12:42:28 | User: Unknown | Action: Edit State | Details:
-Timestamp: 2026-03-22 12:42:37 | User: Unknown | Action: Edit State | Details:
-Timestamp: 2026-03-22 12:42:42 | User: Unknown | Action: Delete State | Details:
-Timestamp: 2026-03-22 12:45:49 | User: Unknown | Action: Add Payment | Details:
-Timestamp: 2026-03-22 12:46:08 | User: Unknown | Action: Edit Payment | Details:
-Timestamp: 2026-03-22 12:46:14 | User: Unknown | Action: Delete Payment | Details:
-Timestamp: 2026-03-22 13:00:54 | User: Unknown | Action: Get hold type | Details:
-Timestamp: 2026-03-22 13:16:59 | User: Unknown | Action: Check State | Details:
-Timestamp: 2026-03-22 13:17:00 | User: Unknown | Action: Add State | Details:
-Timestamp: 2026-03-22 13:17:08 | User: Unknown | Action: Edit State | Details:
-Timestamp: 2026-03-22 13:17:12 | User: Unknown | Action: Delete State | Details:
-Timestamp: 2026-03-22 13:17:16 | User: Unknown | Action: Check State | Details:
-Timestamp: 2026-03-22 13:17:16 | User: Unknown | Action: Check State | Details:
-Timestamp: 2026-03-22 13:17:17 | User: Unknown | Action: Check State | Details:
-Timestamp: 2026-03-22 13:17:17 | User: Unknown | Action: Check State | Details:
-Timestamp: 2026-03-22 13:17:17 | User: Unknown | Action: Check State | Details:
-Timestamp: 2026-03-22 13:17:17 | User: Unknown | Action: Check State | Details:
-Timestamp: 2026-03-22 13:17:34 | User: Unknown | Action: Add Subcontractor | Details:
-Timestamp: 2026-03-22 13:17:43 | User: Unknown | Action: Edit Subcontractor | Details:
-Timestamp: 2026-03-22 13:18:07 | User: Unknown | Action: Edit Subcontractor | Details:
-Timestamp: 2026-03-22 14:41:43 | User: Unknown | Action: Login | Details:
-Timestamp: 2026-03-22 14:41:52 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:41:53 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:32 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:32 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:33 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:33 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:33 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:33 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:34 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:34 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:34 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:34 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:34 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:34 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:35 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:35 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:35 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:35 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:35 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:36 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:36 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:37 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:37 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:38 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:38 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:38 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:39 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:39 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:39 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:40 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:40 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:40 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:40 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:41 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:41 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:41 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:41 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:41 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:42 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:42 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:42 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:42 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:43 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:43 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:43 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:43 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:43 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:44 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:44 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:44 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:44 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:45 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:45 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:45 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:45 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:45 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:46 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:46 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:55 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:55 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:57 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:43:57 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:44:18 | User: Unknown | Action: Upload Excel File | Details:
-Timestamp: 2026-03-22 14:44:26 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:44:26 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:44:26 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:44:27 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:44:27 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:44:27 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:44:27 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:44:41 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:44:51 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:12 | User: Unknown | Action: Upload Excel File | Details:
-Timestamp: 2026-03-22 14:46:18 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:18 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:18 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:18 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:18 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:18 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:18 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:18 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 14:46:29 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:29 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:31 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:31 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:31 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:31 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:34 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:34 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:35 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:35 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:35 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:35 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:35 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:35 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:37 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:38 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:39 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:39 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:39 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:40 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:40 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:40 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:40 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:40 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:41 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:46:43 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 14:47:00 | User: Unknown | Action: Get hold type | Details:
-Timestamp: 2026-03-22 15:43:40 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:43:41 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:43:41 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:43:41 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:43:41 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:43:42 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:43:42 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:43:42 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:43:42 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:43:42 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:43:43 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:43:43 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:43:43 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:43:44 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:43:44 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:43:44 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:43:44 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:43:44 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:43:45 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:43:47 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:44:25 | User: Unknown | Action: Get hold type | Details:
-Timestamp: 2026-03-22 15:46:11 | User: Unknown | Action: Delete Payment | Details:
-Timestamp: 2026-03-22 15:46:49 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:46:49 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:46:50 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:47:09 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:47:09 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:47:09 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:52:16 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:52:18 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:55:27 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:55:27 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:55:27 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:55:29 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:55:31 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:55:32 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:55:33 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:49 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:50 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:50 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:51 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:51 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:51 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:51 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:52 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:52 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:52 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:52 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:52 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:52 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:53 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:53 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:53 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:53 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:53 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:53 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:53 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:53 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:53 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:53 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:54 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:57:54 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:58:07 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:58:08 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:58:08 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:58:10 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:58:10 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:58:10 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:58:10 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:58:12 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 15:58:12 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 16:11:47 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 16:11:48 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 16:25:22 | User: Unknown | Action: Get hold type | Details:
-Timestamp: 2026-03-22 16:26:30 | User: Unknown | Action: Get hold type | Details:
-Timestamp: 2026-03-22 16:27:56 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 16:27:57 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 17:12:59 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 17:13:00 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 17:32:37 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 17:32:39 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 17:49:52 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 17:49:56 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 17:52:53 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 17:52:55 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 18:04:04 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 18:04:09 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 18:04:15 | User: Unknown | Action: Download PMC Report | Details:
-Timestamp: 2026-03-22 18:07:07 | User: Unknown | Action: Download PMC Report | Details:
-Timestamp: 2026-03-22 18:11:40 | User: Unknown | Action: Download PMC Report | Details:
-Timestamp: 2026-03-22 18:15:29 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 18:15:31 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 18:15:37 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 18:15:38 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 18:15:41 | User: Unknown | Action: Download PMC Report | Details:
-Timestamp: 2026-03-22 18:18:47 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 18:18:48 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 18:30:11 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 18:30:14 | User: Unknown | Action: Search Contractor | Details:
-Timestamp: 2026-03-22 18:34:50 | User: Unknown | Action: Download PMC Report | Details:
-Timestamp: 2026-03-22 18:52:52 | User: Unknown | Action: Upload Excel File | Details:
-Timestamp: 2026-03-22 18:52:55 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 18:52:55 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 18:52:55 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 18:52:55 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 18:52:55 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 18:52:55 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 18:52:55 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 18:52:55 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 18:52:55 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 18:52:55 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 18:52:55 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 18:52:55 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 18:52:55 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 18:52:55 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 18:52:55 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 18:52:55 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 18:52:55 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 18:52:55 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 18:52:55 | User: Unknown | Action: Data saved | Details:
-Timestamp: 2026-03-22 18:52:55 | User: Unknown | Action: Data saved | Details:
+Timestamp: 2026-03-22 13:44:03 | User: Unknown | Action: Login | Details:
+Timestamp: 2026-03-22 13:51:01 | User: Unknown | Action: Check Block | Details:
+Timestamp: 2026-03-22 13:51:01 | User: Unknown | Action: Check Block | Details:
+Timestamp: 2026-03-22 13:51:01 | User: Unknown | Action: Check Block | Details:
+Timestamp: 2026-03-22 13:51:01 | User: Unknown | Action: Check Block | Details:
+Timestamp: 2026-03-22 13:51:03 | User: Unknown | Action: Check Block | Details:
+Timestamp: 2026-03-22 13:51:04 | User: Unknown | Action: Add Block | Details:
+Timestamp: 2026-03-22 13:51:45 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 13:51:46 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 13:51:46 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 13:51:46 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 13:51:46 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 13:51:47 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 13:51:47 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 13:51:49 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 13:51:49 | User: Unknown | Action: Add Village | Details:
+Timestamp: 2026-03-22 14:02:44 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:02:44 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:02:45 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:02:45 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:02:45 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:02:46 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:02:46 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:02:46 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:02:46 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:02:46 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:02:46 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:02:47 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:02:47 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:02:49 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:02:49 | User: Unknown | Action: Add Village | Details:
+Timestamp: 2026-03-22 14:41:45 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:41:45 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:41:45 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:41:46 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:41:46 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:41:46 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:41:47 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:41:48 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 14:41:48 | User: Unknown | Action: Add Village | Details:
+Timestamp: 2026-03-22 14:42:03 | User: Unknown | Action: Delete Village | Details:
+Timestamp: 2026-03-22 14:46:40 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 14:46:46 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:13:08 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:14:05 | User: Unknown | Action: Add invoice | Details:
+Timestamp: 2026-03-22 16:14:10 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:22:44 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:24:26 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:24:26 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:24:27 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:24:27 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:24:27 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:24:27 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:24:27 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:24:28 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:24:28 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:24:28 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:24:28 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:24:28 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:24:28 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:24:29 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:24:52 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:36:04 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:36:05 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:44:04 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:44:05 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:44:16 | User: Unknown | Action: Delete Invoice | Details:
+Timestamp: 2026-03-22 16:44:29 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:46:02 | User: Unknown | Action: Edit invoice | Details:
+Timestamp: 2026-03-22 16:46:13 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:46:39 | User: Unknown | Action: Edit invoice | Details:
+Timestamp: 2026-03-22 16:46:46 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:46:58 | User: Unknown | Action: Delete Invoice | Details:
+Timestamp: 2026-03-22 16:48:39 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:55:40 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:57:59 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:58:19 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:58:19 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:58:20 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:58:20 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 16:58:20 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:01:33 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:01:34 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:01:34 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:01:34 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:01:34 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:04:33 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:07:03 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:09:23 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:10:08 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:12:47 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:12:48 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:12:48 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:12:49 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:15:32 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:15:32 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:15:32 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:15:32 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:15:33 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:19:27 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:19:27 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:19:27 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:19:27 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:19:32 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:19:32 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:19:39 | User: Unknown | Action: Delete Invoice | Details:
+Timestamp: 2026-03-22 17:31:10 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:31:26 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:31:36 | User: Unknown | Action: Delete Invoice | Details:
+Timestamp: 2026-03-22 17:31:42 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:32:24 | User: Unknown | Action: Edit invoice | Details:
+Timestamp: 2026-03-22 17:32:31 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:33:48 | User: Unknown | Action: Add invoice | Details:
+Timestamp: 2026-03-22 17:33:50 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:34:01 | User: Unknown | Action: Delete Invoice | Details:
+Timestamp: 2026-03-22 17:34:24 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:34:41 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:49:57 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:50:06 | User: Unknown | Action: Delete Invoice | Details:
+Timestamp: 2026-03-22 17:54:09 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 17:57:09 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 18:24:21 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 18:24:29 | User: Unknown | Action: Delete Invoice | Details:
+Timestamp: 2026-03-22 18:24:33 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 18:25:34 | User: Unknown | Action: Edit invoice | Details:
+Timestamp: 2026-03-22 18:25:43 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 18:38:34 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 18:38:40 | User: Unknown | Action: Delete invoice | Details:
+Timestamp: 2026-03-22 18:39:42 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 18:41:47 | User: Unknown | Action: Get hold type | Details:
+Timestamp: 2026-03-22 18:42:08 | User: Unknown | Action: Delete Village | Details:
+Timestamp: 2026-03-22 18:42:16 | User: Unknown | Action: Delete Village | Details:
+Timestamp: 2026-03-22 18:43:44 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 18:43:44 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 18:43:44 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 18:43:45 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 18:43:45 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 18:43:46 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 18:43:46 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 18:43:47 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 18:43:50 | User: Unknown | Action: Check Village | Details:
+Timestamp: 2026-03-22 18:43:51 | User: Unknown | Action: Add Village | Details:
+Timestamp: 2026-03-22 18:47:22 | User: Unknown | Action: Edit Village | Details:
+Timestamp: 2026-03-22 18:51:57 | User: Unknown | Action: Edit Village | Details:
+Timestamp: 2026-03-22 18:53:38 | User: Unknown | Action: Edit Village | Details:
+Timestamp: 2026-03-22 18:57:49 | User: Unknown | Action: Edit Village | Details:
+Timestamp: 2026-03-22 19:00:14 | User: Unknown | Action: Edit Village | Details:
+Timestamp: 2026-03-22 19:03:21 | User: Unknown | Action: Edit Village | Details:
+Timestamp: 2026-03-22 19:06:23 | User: Unknown | Action: Edit Village | Details:
+Timestamp: 2026-03-22 19:10:30 | User: Unknown | Action: Edit Village | Details:
+Timestamp: 2026-03-22 19:10:41 | User: Unknown | Action: Delete Village | Details:
+Timestamp: 2026-03-23 11:55:40 | User: Unknown | Action: Add GST Release | Details:
diff --git a/controllers/excel_upload_controller.py b/controllers/excel_upload_controller.py
index 0f543d5..d4c0f45 100644
--- a/controllers/excel_upload_controller.py
+++ b/controllers/excel_upload_controller.py
@@ -6,21 +6,20 @@ import openpyxl
from flask import Blueprint, request, render_template, redirect, url_for, jsonify, current_app
from flask_login import current_user
from model.Log import LogHelper
-import config
-from model.FolderAndFile import FolderAndFile
+import config # your database connection module
excel_bp = Blueprint('excel', __name__)
# Default folder in case config not set
-# DEFAULT_UPLOAD_FOLDER = 'uploads'
+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
+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 ----------------
@@ -30,11 +29,8 @@ def upload():
if request.method == 'POST':
file = request.files.get('file')
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)
-
+ upload_folder = get_upload_folder()
+ filepath = os.path.join(upload_folder, file.filename)
file.save(filepath)
LogHelper.log_action(
@@ -51,8 +47,7 @@ def show_table(filename):
global data
data = []
- # filepath = os.path.join(get_upload_folder(), filename)
- filepath = FolderAndFile.get_upload_path(filename)
+ filepath = os.path.join(get_upload_folder(), filename)
wb = openpyxl.load_workbook(filepath, data_only=True)
sheet = wb.active
@@ -74,6 +69,7 @@ def show_table(filename):
try:
cursor = connection.cursor(dictionary=True)
+ print(f"Calling GetStateByName with: {file_info['State']}")
cursor.callproc('GetStateByName', [file_info['State']])
for result in cursor.stored_results():
state_data = result.fetchone()
@@ -81,6 +77,7 @@ def show_table(filename):
errors.append(f"State '{file_info['State']}' is not valid. Please add it.")
if state_data:
+ print(f"Calling GetDistrictByNameAndStates with: {file_info['District']}, {state_data['State_ID']}")
cursor.callproc('GetDistrictByNameAndStates', [file_info['District'], state_data['State_ID']])
for result in cursor.stored_results():
district_data = result.fetchone()
@@ -88,23 +85,27 @@ def show_table(filename):
errors.append(f"District '{file_info['District']}' is not valid under state '{file_info['State']}'.")
if district_data:
+ print(f"Calling GetBlockByNameAndDistricts with: {file_info['Block']}, {district_data['District_ID']}")
cursor.callproc('GetBlockByNameAndDistricts', [file_info['Block'], district_data['District_ID']])
for result in cursor.stored_results():
block_data = result.fetchone()
if not block_data:
errors.append(f"Block '{file_info['Block']}' is not valid under district '{file_info['District']}'.")
+ print(f"Calling GetSubcontractorByName with: {file_info['Subcontractor']}")
cursor.callproc('GetSubcontractorByName', [file_info['Subcontractor']])
for result in cursor.stored_results():
subcontractor_data = result.fetchone()
if not subcontractor_data:
+ print(f"Inserting subcontractor: {file_info['Subcontractor']}")
cursor.callproc('InsertSubcontractor', [file_info['Subcontractor']])
connection.commit()
cursor.callproc('GetSubcontractorByName', [file_info['Subcontractor']])
for result in cursor.stored_results():
subcontractor_data = result.fetchone()
+ print("Calling GetAllHoldTypes")
cursor.callproc("GetAllHoldTypes")
hold_types_data = []
for ht in cursor.stored_results():
diff --git a/controllers/invoice_controller.py b/controllers/invoice_controller.py
index d8af37a..cbc29fc 100644
--- a/controllers/invoice_controller.py
+++ b/controllers/invoice_controller.py
@@ -1,98 +1,200 @@
+# # controllers/invoice_controller.py
+
+# from flask import Blueprint, request, jsonify, render_template
+# from flask_login import login_required, current_user
+# from model.Invoice import *
+# from model.Log import LogHelper
+
+# invoice_bp = Blueprint('invoice', __name__)
+
+# # -------------------------------- Add Invoice ---------------------------------
+# @invoice_bp.route('/add_invoice', methods=['GET', 'POST'])
+# @login_required
+# def add_invoice():
+# if request.method == 'POST':
+# try:
+# village_name = request.form.get('village')
+# village_result = get_village_id(village_name)
+
+# if not village_result:
+# return jsonify({"status": "error", "message": f"Village '{village_name}' not found"}), 400
+
+# village_id = village_result['Village_Id']
+# data = request.form
+
+# invoice_id = insert_invoice(data, village_id)
+# assign_subcontractor(data, village_id)
+# insert_hold_types(data, invoice_id)
+
+# LogHelper.log_action("Add invoice", f"User {current_user.id} Added invoice '{data.get('pmc_no')}'")
+
+# return jsonify({"status": "success", "message": "Invoice added successfully"}), 201
+
+# except Exception as e:
+# return jsonify({"status": "error", "message": str(e)}), 500
+
+# invoices = get_all_invoice_details()
+# villages = get_all_villages()
+# return render_template('add_invoice.html', invoices=invoices, villages=villages)
+
+
+# # ------------------- Search Subcontractor -------------------
+# @invoice_bp.route('/search_subcontractor', methods=['POST'])
+# @login_required
+# def search_subcontractor():
+# sub_query = request.form.get("query")
+# results = search_contractors(sub_query)
+
+# if not results:
+# return "
No subcontractor found"
+
+# output = "".join(
+# f"{row['Contractor_Name']}"
+# for row in results
+# )
+# return output
+
+
+# # ------------------- Get Hold Types -------------------
+# @invoice_bp.route('/get_hold_types', methods=['GET'])
+# @login_required
+# def get_hold_types():
+# hold_types = get_all_hold_types()
+# LogHelper.log_action("Get hold type", f"User {current_user.id} Get hold type '{hold_types}'")
+# return jsonify(hold_types)
+
+
+# # ------------------- Edit Invoice -------------------
+# @invoice_bp.route('/edit_invoice/', methods=['GET', 'POST'])
+# @login_required
+# def edit_invoice(invoice_id):
+# if request.method == 'POST':
+# data = request.form
+# update_invoice(data, invoice_id)
+# update_inpayment(data)
+
+# LogHelper.log_action("Edit invoice", f"User {current_user.id} Edit invoice '{invoice_id}'")
+# return jsonify({"status": "success", "message": "Invoice updated successfully"}), 200
+
+# invoice = get_invoice_by_id(invoice_id)
+# return render_template('edit_invoice.html', invoice=invoice)
+
+
+# # ------------------- Delete Invoice -------------------
+# @invoice_bp.route('/delete_invoice/', methods=['GET'])
+# @login_required
+# def delete_invoice_route(invoice_id):
+# try:
+# delete_invoice_data(invoice_id, current_user.id)
+# LogHelper.log_action("Delete Invoice", f"User {current_user.id} deleted Invoice '{invoice_id}'")
+# return jsonify({
+# "message": f"Invoice {invoice_id} deleted successfully.",
+# "status": "success"
+# })
+# except Exception as e:
+# return jsonify({
+# "message": str(e),
+# "status": "error"
+# }), 500
+
+
+
+
# controllers/invoice_controller.py
from flask import Blueprint, request, jsonify, render_template
from flask_login import login_required, current_user
from model.Invoice import *
-from model.Log import LogHelper
+from model.Log import LogHelper
invoice_bp = Blueprint('invoice', __name__)
-# -------------------------------- Add Invoice ---------------------------------
-@invoice_bp.route('/add_invoice', methods=['GET', 'POST'])
-@login_required
-def add_invoice():
- if request.method == 'POST':
+# ------------------------------- Helpers -------------------------------
+def handle_exception(func):
+ """Decorator to handle exceptions and return JSON error responses."""
+ def wrapper(*args, **kwargs):
try:
- village_name = request.form.get('village')
- village_result = get_village_id(village_name)
-
- if not village_result:
- return jsonify({"status": "error", "message": f"Village '{village_name}' not found"}), 400
-
- village_id = village_result['Village_Id']
- data = request.form
-
- invoice_id = insert_invoice(data, village_id)
- assign_subcontractor(data, village_id)
- insert_hold_types(data, invoice_id)
-
- LogHelper.log_action("Add invoice", f"User {current_user.id} Added invoice '{data.get('pmc_no')}'")
-
- return jsonify({"status": "success", "message": "Invoice added successfully"}), 201
-
+ return func(*args, **kwargs)
except Exception as e:
return jsonify({"status": "error", "message": str(e)}), 500
+ wrapper.__name__ = func.__name__
+ return wrapper
+
+def log_action(action: str, detail: str):
+ LogHelper.log_action(action, f"User {current_user.id} {detail}")
+
+
+# ------------------------------- Add Invoice -------------------------------
+@invoice_bp.route('/add_invoice', methods=['GET', 'POST'])
+@login_required
+@handle_exception
+def add_invoice():
+ if request.method == 'POST':
+ data = request.form
+ village_name = data.get('village')
+ village_result = get_village_id(village_name)
+
+ if not village_result:
+ return jsonify({"status": "error", "message": f"Village '{village_name}' not found"}), 400
+
+ village_id = village_result['Village_Id']
+ invoice_id = insert_invoice(data, village_id)
+ assign_subcontractor(data, village_id)
+ insert_hold_types(data, invoice_id)
+
+ log_action("Add invoice", f"added invoice '{data.get('pmc_no')}'")
+ return jsonify({"status": "success", "message": "Invoice added successfully"}), 201
invoices = get_all_invoice_details()
villages = get_all_villages()
return render_template('add_invoice.html', invoices=invoices, villages=villages)
-# ------------------- Search Subcontractor -------------------
+# ------------------------------- Search Subcontractor -------------------------------
@invoice_bp.route('/search_subcontractor', methods=['POST'])
@login_required
+@handle_exception
def search_subcontractor():
- sub_query = request.form.get("query")
- results = search_contractors(sub_query)
+ query = request.form.get("query", "").strip()
+ results = search_contractors(query)
if not results:
return "No subcontractor found"
- output = "".join(
- f"{row['Contractor_Name']}"
- for row in results
- )
- return output
+ return "".join(f"{r['Contractor_Name']}" for r in results)
-# ------------------- Get Hold Types -------------------
+# ------------------------------- Get Hold Types -------------------------------
@invoice_bp.route('/get_hold_types', methods=['GET'])
@login_required
+@handle_exception
def get_hold_types():
hold_types = get_all_hold_types()
- LogHelper.log_action("Get hold type", f"User {current_user.id} Get hold type '{hold_types}'")
+ log_action("Get hold type", f"retrieved hold types '{hold_types}'")
return jsonify(hold_types)
-# ------------------- Edit Invoice -------------------
+# ------------------------------- Edit Invoice -------------------------------
@invoice_bp.route('/edit_invoice/', methods=['GET', 'POST'])
@login_required
+@handle_exception
def edit_invoice(invoice_id):
if request.method == 'POST':
data = request.form
update_invoice(data, invoice_id)
update_inpayment(data)
-
- LogHelper.log_action("Edit invoice", f"User {current_user.id} Edit invoice '{invoice_id}'")
+ log_action("Edit invoice", f"edited invoice '{invoice_id}'")
return jsonify({"status": "success", "message": "Invoice updated successfully"}), 200
invoice = get_invoice_by_id(invoice_id)
return render_template('edit_invoice.html', invoice=invoice)
-# ------------------- Delete Invoice -------------------
+# ------------------------------- Delete Invoice -------------------------------
@invoice_bp.route('/delete_invoice/', methods=['GET'])
@login_required
+@handle_exception
def delete_invoice_route(invoice_id):
- try:
- delete_invoice_data(invoice_id, current_user.id)
- LogHelper.log_action("Delete Invoice", f"User {current_user.id} deleted Invoice '{invoice_id}'")
- return jsonify({
- "message": f"Invoice {invoice_id} deleted successfully.",
- "status": "success"
- })
- except Exception as e:
- return jsonify({
- "message": str(e),
- "status": "error"
- }), 500
\ No newline at end of file
+ delete_invoice_data(invoice_id, current_user.id)
+ log_action("Delete invoice", f"deleted invoice '{invoice_id}'")
+ return jsonify({"status": "success", "message": f"Invoice {invoice_id} deleted successfully."})
\ No newline at end of file
diff --git a/controllers/pmc_report_controller.py b/controllers/pmc_report_controller.py
index 7c92cb7..eaa6f45 100644
--- a/controllers/pmc_report_controller.py
+++ b/controllers/pmc_report_controller.py
@@ -1,13 +1,13 @@
from flask import Blueprint, render_template, send_from_directory
-from flask_login import login_required, current_user
from model.PmcReport import PmcReport
pmc_report_bp = Blueprint("pmc_report", __name__)
@pmc_report_bp.route("/pmc_report/")
-@login_required
def pmc_report(pmc_no):
+
data = PmcReport.get_pmc_report(pmc_no)
+
if not data:
return "No PMC found with this number", 404
@@ -24,7 +24,6 @@ def pmc_report(pmc_no):
)
@pmc_report_bp.route("/download_pmc_report/")
-@login_required
def download_pmc_report(pmc_no):
result = PmcReport.download_pmc_report(pmc_no)
diff --git a/controllers/report_controller.py b/controllers/report_controller.py
index 5810a8a..4518d16 100644
--- a/controllers/report_controller.py
+++ b/controllers/report_controller.py
@@ -3,11 +3,11 @@ from flask_login import login_required, current_user
from model.Report import ReportHelper
from model.Log import LogHelper
import config
+from datetime import datetime
import os
import openpyxl
from openpyxl.styles import Font
from model.ContractorInfo import ContractorInfo
-from model.FolderAndFile import FolderAndFile
report_bp = Blueprint("report", __name__)
@@ -26,17 +26,35 @@ def report_page():
def search_contractor():
subcontractor_name = request.form.get("subcontractor_name")
+ pmc_no = request.form.get("pmc_no")
+ state = request.form.get("state")
+ district = request.form.get("district")
+ block = request.form.get("block")
+ village = request.form.get("village")
+ year_from = request.form.get("year_from")
+ year_to = request.form.get("year_to")
LogHelper.log_action(
"Search Contractor",
- f"User {current_user.id} searched contractor '{subcontractor_name}'"
+ f"User {current_user.id} Search contractor '{subcontractor_name}'"
)
- data = ReportHelper.search_contractor(request)
+ data = ReportHelper.search_contractor(
+ subcontractor_name,
+ pmc_no,
+ state,
+ district,
+ block,
+ village,
+ year_from,
+ year_to
+ )
return jsonify(data)
+
# ---------------- Contractor Report ----------------
+
@report_bp.route('/contractor_report/')
@login_required
def contractor_report(contractor_id):
@@ -49,145 +67,136 @@ def contractor_report(contractor_id):
**data
)
+class FilePathData:
+ downloadReportFolder = "static/download"
+
@report_bp.route('/download_report/')
@login_required
def download_report(contractor_id):
+ try:
+ connection = config.get_db_connection()
+ cursor = connection.cursor(dictionary=True)
- return ReportHelper().download_report(contractor_id=contractor_id)
-
-
+ # -------- Contractor Info --------
+ contractor = ContractorInfo(contractor_id)
+ contInfo = contractor.contInfo
+ if not contInfo:
+ return "No contractor found", 404
-# @report_bp.route('/download_report/')
-# @login_required
-# def download_report(contractor_id):
-# try:
-# connection = config.get_db_connection()
-# cursor = connection.cursor(dictionary=True)
+ # -------- Invoice Data --------
+ cursor.callproc('FetchInvoicesByContractor', [contractor_id])
-# # -------- Contractor Info --------
-# contractor = ContractorInfo(contractor_id)
-# contInfo = contractor.contInfo
+ invoices = []
+ for result in cursor.stored_results():
+ invoices.extend(result.fetchall())
-# if not contInfo:
-# return "No contractor found", 404
+ if not invoices:
+ return "No invoice data found"
-# # -------- Invoice Data --------
-# cursor.callproc('FetchInvoicesByContractor', [contractor_id])
+ # -------- Create Workbook --------
+ workbook = openpyxl.Workbook()
+ sheet = workbook.active
+ sheet.title = "Contractor Report"
-# invoices = []
-# for result in cursor.stored_results():
-# invoices.extend(result.fetchall())
+ # ================= CONTRACTOR DETAILS =================
+ sheet.append(["SUB CONTRACTOR DETAILS"])
+ sheet.cell(row=sheet.max_row, column=1).font = Font(bold=True)
+ sheet.append([])
-# if not invoices:
-# return "No invoice data found"
+ 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([])
-# # -------- Create Workbook --------
-# workbook = openpyxl.Workbook()
-# sheet = workbook.active
-# sheet.title = "Contractor Report"
+ # ================= 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)
-# # ================= CONTRACTOR DETAILS =================
-# sheet.append(["SUB CONTRACTOR DETAILS"])
-# sheet.cell(row=sheet.max_row, column=1).font = Font(bold=True)
-# sheet.append([])
+ # ================= DATA =================
+ total_final = 0
+ total_payment = 0
+ total_amount = 0
-# 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([])
+ 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")
+ ]
-# # ================= 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)
+ 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)
-# # ================= DATA =================
-# total_final = 0
-# total_payment = 0
-# total_amount = 0
+ sheet.append(row)
-# 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 ROW =================
+ sheet.append([])
+ sheet.append([
+ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+ "TOTAL",
+ total_final,
+ total_payment,
+ "",
+ total_amount,
+ ""
+ ])
-# 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)
+ # ================= 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
-# sheet.append(row)
+ # ================= 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)
+ workbook.save(output_file)
-# # ================= TOTAL ROW =================
-# sheet.append([])
-# sheet.append([
-# "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
-# "TOTAL",
-# total_final,
-# total_payment,
-# "",
-# total_amount,
-# ""
-# ])
+ return send_file(output_file, as_attachment=True)
-# # ================= 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)
\ No newline at end of file
+ except Exception as e:
+ return str(e)
\ No newline at end of file
diff --git a/controllers/subcontractor_controller.py b/controllers/subcontractor_controller.py
index 884ed6a..7416507 100644
--- a/controllers/subcontractor_controller.py
+++ b/controllers/subcontractor_controller.py
@@ -1,12 +1,12 @@
+# controllers/subcontractor_controller.py
+
from flask import Blueprint, render_template, request, redirect, url_for, jsonify
from flask_login import login_required
from model.Subcontractor import Subcontractor
-
+from model.Log import LogHelper
subcontractor_bp = Blueprint('subcontractor', __name__)
-# ----------------------------------------------------------
-# Helpers (unchanged)
-# ----------------------------------------------------------
+# Simple replacements for missing HtmlHelper and ResponseHandler
class HtmlHelper:
@staticmethod
def json_response(data, status=200):
@@ -30,88 +30,71 @@ class ResponseHandler:
return {"status": "error", "message": f"Failed to delete {entity}"}
-# ----------------------------------------------------------
-# LIST + ADD
-# ----------------------------------------------------------
@subcontractor_bp.route('/subcontractor', methods=['GET', 'POST'])
@login_required
def subcontract():
+ subcontractor = []
- sub = Subcontractor()
-
- # ---------------- GET ----------------
if request.method == 'GET':
- subcontractor = sub.GetAllSubcontractors(request)
+ subcontractor, error = Subcontractor.get_all_subcontractors()
+ if error:
+ return HtmlHelper.json_response(ResponseHandler.fetch_failure("Subcontractor"), 500)
- if not sub.isSuccess:
- return HtmlHelper.json_response(
- ResponseHandler.fetch_failure("Subcontractor"), 500
- )
-
- return render_template('add_subcontractor.html', subcontractor=subcontractor)
-
- # ---------------- POST (ADD) ----------------
if request.method == 'POST':
+ contractor_data = {
+ 'Contractor_Name': request.form['Contractor_Name'],
+ 'Address': request.form['Address'],
+ 'Mobile_No': request.form['Mobile_No'],
+ 'PAN_No': request.form['PAN_No'],
+ 'Email': request.form['Email'],
+ 'Gender': request.form['Gender'],
+ 'GST_Registration_Type': request.form['GST_Registration_Type'],
+ 'GST_No': request.form['GST_No'],
+ 'Contractor_password': request.form['Contractor_password'],
+ }
+ error = Subcontractor.save_subcontractor(contractor_data)
+ if error:
+ return HtmlHelper.json_response(ResponseHandler.add_failure("Subcontractor"), 500)
+ subcontractor, _ = Subcontractor.get_all_subcontractors()
- sub.AddSubcontractor(request)
-
- if not sub.isSuccess:
- return HtmlHelper.json_response(
- ResponseHandler.add_failure("Subcontractor"), 500
- )
-
- # Reload list after insert
- subcontractor = sub.GetAllSubcontractors(request)
-
- return render_template('add_subcontractor.html', subcontractor=subcontractor)
+ return render_template('add_subcontractor.html', subcontractor=subcontractor)
-# ----------------------------------------------------------
-# EDIT
-# ----------------------------------------------------------
@subcontractor_bp.route('/edit_subcontractor/', methods=['GET', 'POST'])
@login_required
def edit_subcontractor(id):
-
- sub = Subcontractor()
-
- # Fetch data
- subcontractor = sub.GetSubcontractorByID(id)
-
+ subcontractor, error = Subcontractor.get_subcontractor_by_id(id)
+ if error:
+ return HtmlHelper.json_response(ResponseHandler.fetch_failure("Subcontractor"), 500)
if not subcontractor:
- return HtmlHelper.json_response(
- ResponseHandler.fetch_failure("Subcontractor"), 404
- )
+ return HtmlHelper.json_response(ResponseHandler.fetch_failure("Subcontractor"), 404)
- # ---------------- POST (UPDATE) ----------------
if request.method == 'POST':
-
- sub.EditSubcontractor(request, id)
-
- if not sub.isSuccess:
- return HtmlHelper.json_response(
- ResponseHandler.update_failure("Subcontractor"), 500
- )
-
+ updated_data = {
+ 'Contractor_Name': request.form['Contractor_Name'],
+ 'Address': request.form['Address'],
+ 'Mobile_No': request.form['Mobile_No'],
+ 'PAN_No': request.form['PAN_No'],
+ 'Email': request.form['Email'],
+ 'Gender': request.form['Gender'],
+ 'GST_Registration_Type': request.form['GST_Registration_Type'],
+ 'GST_No': request.form['GST_No'],
+ 'Contractor_password': request.form['Contractor_password'],
+ }
+ error = Subcontractor.update_subcontractor(id, updated_data)
+ if error:
+ return HtmlHelper.json_response(ResponseHandler.update_failure("Subcontractor"), 500)
return redirect(url_for('subcontractor.subcontract'))
return render_template('edit_subcontractor.html', subcontractor=subcontractor)
-# ----------------------------------------------------------
-# DELETE
-# ----------------------------------------------------------
@subcontractor_bp.route('/deleteSubContractor/', methods=['GET', 'POST'])
@login_required
def deleteSubContractor(id):
-
- sub = Subcontractor()
-
- sub.DeleteSubcontractor(request, id)
-
- if not sub.isSuccess:
- return HtmlHelper.json_response(
- ResponseHandler.delete_failure("Subcontractor"), 500
- )
-
+ error, affected_rows = Subcontractor.delete_subcontractor(id)
+ if error:
+ return HtmlHelper.json_response(ResponseHandler.delete_failure("Subcontractor"), 500)
+ if affected_rows == 0:
+ return HtmlHelper.json_response(ResponseHandler.fetch_failure("Subcontractor not deleted"), 404)
return redirect(url_for('subcontractor.subcontract'))
\ No newline at end of file
diff --git a/controllers/village_controller.py b/controllers/village_controller.py
index 02df862..37bf441 100644
--- a/controllers/village_controller.py
+++ b/controllers/village_controller.py
@@ -1,8 +1,177 @@
+# from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify
+# from flask_login import login_required
+
+# import config
+
+# from model.Village import Village
+# from model.State import State
+
+# # Create Blueprint
+# village_bp = Blueprint('village', __name__)
+
+
+# # ------------------------- Add Village -------------------------
+# @village_bp.route('/add_village', methods=['GET', 'POST'])
+# @login_required
+# def add_village():
+
+# village = Village()
+
+# if request.method == 'POST':
+# village.AddVillage(request=request)
+# return village.resultMessage
+
+# state = State()
+# states = state.GetAllStates(request=request)
+
+# villages = village.GetAllVillages(request=request)
+
+# return render_template(
+# 'add_village.html',
+# states=states,
+# villages=villages
+# )
+
+
+# # ------------------------- Fetch Districts -------------------------
+# @village_bp.route('/get_districts/')
+# @login_required
+# def get_districts(state_id):
+
+# connection = config.get_db_connection()
+# cursor = connection.cursor()
+
+# cursor.callproc("GetDistrictByStateID", [state_id])
+
+# districts = []
+
+# for rs in cursor.stored_results():
+# districts = rs.fetchall()
+
+# cursor.close()
+# connection.close()
+
+# district_list = []
+
+# for d in districts:
+# district_list.append({
+# "id": d[0],
+# "name": d[1]
+# })
+
+# return jsonify(district_list)
+
+
+# # ------------------------- Fetch Blocks -------------------------
+# @village_bp.route('/get_blocks/')
+# @login_required
+# def get_blocks(district_id):
+
+# connection = config.get_db_connection()
+# cursor = connection.cursor()
+
+# cursor.callproc("GetBlocksByDistrictID", [district_id])
+
+# blocks = []
+
+# for rs in cursor.stored_results():
+# blocks = rs.fetchall()
+
+# cursor.close()
+# connection.close()
+
+# block_list = []
+
+# for b in blocks:
+# block_list.append({
+# "id": b[0],
+# "name": b[1]
+# })
+
+# return jsonify(block_list)
+
+
+# # ------------------------- Check Village -------------------------
+# @village_bp.route('/check_village', methods=['POST'])
+# @login_required
+# def check_village():
+
+# village = Village()
+# return village.CheckVillage(request=request)
+
+
+# # ------------------------- Delete Village -------------------------
+# @village_bp.route('/delete_village/')
+# @login_required
+# def delete_village(village_id):
+
+# village = Village()
+
+# village.DeleteVillage(request=request, village_id=village_id)
+
+# if not village.isSuccess:
+# flash(village.resultMessage, "error")
+# else:
+# flash(village.resultMessage, "success")
+
+# return redirect(url_for('village.add_village'))
+
+
+# # ------------------------- Edit Village -------------------------
+# @village_bp.route('/edit_village/', methods=['GET', 'POST'])
+# @login_required
+# def edit_village(village_id):
+
+# village = Village()
+
+# if request.method == 'POST':
+
+# village.EditVillage(request=request, village_id=village_id)
+
+# if village.isSuccess:
+# flash(village.resultMessage, "success")
+# return redirect(url_for('village.add_village'))
+
+# else:
+# flash(village.resultMessage, "error")
+
+# village_data = village.GetVillageByID(id=village_id)
+# blocks = village.GetAllBlocks()
+
+# return render_template(
+# 'edit_village.html',
+# village_data=village_data,
+# blocks=blocks
+# )
+
+# else:
+
+# village_data = village.GetVillageByID(request=request, id=village_id)
+
+# if not village.isSuccess:
+# flash(village.resultMessage, "error")
+# return redirect(url_for('village.add_village'))
+
+# blocks = village.GetAllBlocks(request=request)
+
+# if village_data is None:
+# village_data = []
+
+# if blocks is None:
+# blocks = []
+
+# return render_template(
+# 'edit_village.html',
+# village_data=village_data,
+# blocks=blocks
+# )
+
+
+
from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify
from flask_login import login_required
import config
-
from model.Village import Village
from model.State import State
@@ -23,7 +192,6 @@ def add_village():
state = State()
states = state.GetAllStates(request=request)
-
villages = village.GetAllVillages(request=request)
return render_template(
@@ -42,7 +210,6 @@ def get_districts(state_id):
cursor = connection.cursor()
cursor.callproc("GetDistrictByStateID", [state_id])
-
districts = []
for rs in cursor.stored_results():
@@ -51,15 +218,7 @@ def get_districts(state_id):
cursor.close()
connection.close()
- district_list = []
-
- for d in districts:
- district_list.append({
- "id": d[0],
- "name": d[1]
- })
-
- return jsonify(district_list)
+ return jsonify([{"id": d[0], "name": d[1]} for d in districts])
# ------------------------- Fetch Blocks -------------------------
@@ -71,7 +230,6 @@ def get_blocks(district_id):
cursor = connection.cursor()
cursor.callproc("GetBlocksByDistrictID", [district_id])
-
blocks = []
for rs in cursor.stored_results():
@@ -80,22 +238,13 @@ def get_blocks(district_id):
cursor.close()
connection.close()
- block_list = []
-
- for b in blocks:
- block_list.append({
- "id": b[0],
- "name": b[1]
- })
-
- return jsonify(block_list)
+ return jsonify([{"id": b[0], "name": b[1]} for b in blocks])
# ------------------------- Check Village -------------------------
@village_bp.route('/check_village', methods=['POST'])
@login_required
def check_village():
-
village = Village()
return village.CheckVillage(request=request)
@@ -106,14 +255,9 @@ def check_village():
def delete_village(village_id):
village = Village()
-
village.DeleteVillage(request=request, village_id=village_id)
- if not village.isSuccess:
- flash(village.resultMessage, "error")
- else:
- flash(village.resultMessage, "success")
-
+ flash(village.resultMessage, "success" if village.isSuccess else "error")
return redirect(url_for('village.add_village'))
@@ -135,8 +279,8 @@ def edit_village(village_id):
else:
flash(village.resultMessage, "error")
- village_data = village.GetVillageByID(request=request, id=village_id)
- blocks = village.GetAllBlocks(request=request)
+ village_data = village.GetVillageByID(id=village_id) or []
+ blocks = village.GetAllBlocks() or []
return render_template(
'edit_village.html',
@@ -145,23 +289,17 @@ def edit_village(village_id):
)
else:
-
- village_data = village.GetVillageByID(request=request, id=village_id)
+ # ✅ FIXED HERE (removed request)
+ village_data = village.GetVillageByID(id=village_id)
if not village.isSuccess:
flash(village.resultMessage, "error")
return redirect(url_for('village.add_village'))
- blocks = village.GetAllBlocks(request=request)
-
- if village_data is None:
- village_data = []
-
- if blocks is None:
- blocks = []
+ blocks = village.GetAllBlocks() or []
return render_template(
'edit_village.html',
- village_data=village_data,
+ village_data=village_data or [],
blocks=blocks
)
\ No newline at end of file
diff --git a/downloads/Contractor_Report_1.xlsx b/downloads/Contractor_Report_1.xlsx
new file mode 100644
index 0000000..0896efe
Binary files /dev/null and b/downloads/Contractor_Report_1.xlsx differ
diff --git a/downloads/Contractor_Report_2.xlsx b/downloads/Contractor_Report_2.xlsx
new file mode 100644
index 0000000..076f8e2
Binary files /dev/null and b/downloads/Contractor_Report_2.xlsx differ
diff --git a/downloads/Contractor_Report_3.xlsx b/downloads/Contractor_Report_3.xlsx
new file mode 100644
index 0000000..db43efa
Binary files /dev/null and b/downloads/Contractor_Report_3.xlsx differ
diff --git a/downloads/Contractor_Report_4.xlsx b/downloads/Contractor_Report_4.xlsx
new file mode 100644
index 0000000..d890e65
Binary files /dev/null and b/downloads/Contractor_Report_4.xlsx differ
diff --git a/downloads/Contractor_Report_6.xlsx b/downloads/Contractor_Report_6.xlsx
new file mode 100644
index 0000000..ee7a7c1
Binary files /dev/null and b/downloads/Contractor_Report_6.xlsx differ
diff --git a/downloads/Contractor_Report_Aadi Shakti Construction.xlsx b/downloads/Contractor_Report_Aadi Shakti Construction.xlsx
new file mode 100644
index 0000000..2738768
Binary files /dev/null and b/downloads/Contractor_Report_Aadi Shakti Construction.xlsx differ
diff --git a/downloads/Contractor_Report_Aarham Enterprises.xlsx b/downloads/Contractor_Report_Aarham Enterprises.xlsx
new file mode 100644
index 0000000..6728f49
Binary files /dev/null and b/downloads/Contractor_Report_Aarham Enterprises.xlsx differ
diff --git a/downloads/Contractor_Report_Aashirwad Enterprises.xlsx b/downloads/Contractor_Report_Aashirwad Enterprises.xlsx
new file mode 100644
index 0000000..b5a0701
Binary files /dev/null and b/downloads/Contractor_Report_Aashirwad Enterprises.xlsx differ
diff --git a/downloads/Contractor_Report_JANARDAN ORGANIC FOOD MILLS.xlsx b/downloads/Contractor_Report_JANARDAN ORGANIC FOOD MILLS.xlsx
new file mode 100644
index 0000000..9a0eee0
Binary files /dev/null and b/downloads/Contractor_Report_JANARDAN ORGANIC FOOD MILLS.xlsx differ
diff --git a/model/ContractorInfo.py b/model/ContractorInfo.py
index a4eb36b..edcfafd 100644
--- a/model/ContractorInfo.py
+++ b/model/ContractorInfo.py
@@ -1,72 +1,136 @@
-import mysql.connector
+# import mysql.connector
+# from mysql.connector import Error
+# import config
+# import openpyxl
+# import os
+# import re
+# import ast
+# from datetime import datetime
+
+
+# class ContractorInfo:
+# ID = ""
+# contInfo = None
+# def __init__(self, id):
+# self.ID = id
+# print(id)
+# self.fetchData()
+
+# def fetchData(self):
+# try:
+# connection = config.get_db_connection()
+# cursor = connection.cursor(dictionary=True, buffered=True)
+# print("here", flush=True)
+
+# cursor.callproc('GetContractorInfoById', [self.ID])
+# for result in cursor.stored_results():
+# self.contInfo = result.fetchone()
+
+# print(self.contInfo,flush=True)
+# finally:
+# cursor.close()
+# connection.close()
+
+# def fetchalldata(self):
+
+# try:
+# connection = config.get_db_connection()
+# cursor = connection.cursor(dictionary=True, buffered=True)
+# print("here", flush=True)
+
+
+# # ---------------- Hold Types ----------------
+# cursor = connection.cursor(dictionary=True)
+
+# cursor.callproc('GetHoldTypesByContractor', [self.ID])
+
+# hold_types = []
+# for result in cursor.stored_results():
+# hold_types = result.fetchall()
+# hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types}
+
+# # ---------------- Invoices ----------------
+# cursor = connection.cursor(dictionary=True)
+
+# cursor.callproc('GetInvoicesByContractor', [self.ID])
+
+# invoices = []
+# for result in cursor.stored_results():
+# invoices = result.fetchall()
+
+# # Remove duplicate invoices
+# invoice_ids_seen = set()
+# unique_invoices = []
+# for inv in invoices:
+# if inv["Invoice_Id"] not in invoice_ids_seen:
+# invoice_ids_seen.add(inv["Invoice_Id"])
+# unique_invoices.append(inv)
+# invoices = unique_invoices
+
+# finally:
+# cursor.close()
+# connection.close()
+
+
from mysql.connector import Error
import config
-import openpyxl
-import os
-import re
-import ast
from datetime import datetime
class ContractorInfo:
- ID = ""
- contInfo = None
- def __init__(self, id):
- self.ID = id
- print(id)
+ def __init__(self, contractor_id):
+ self.ID = contractor_id
+ self.contInfo = None
self.fetchData()
def fetchData(self):
+ """Fetch basic contractor info by ID."""
try:
connection = config.get_db_connection()
- cursor = connection.cursor(dictionary=True, buffered=True)
- cursor.callproc('GetContractorInfoById', [self.ID])
- for result in cursor.stored_results():
- self.contInfo = result.fetchone()
-
- print(self.contInfo,flush=True)
+ with connection.cursor(dictionary=True, buffered=True) as cursor:
+ cursor.callproc('GetContractorInfoById', [self.ID])
+ # Get the first result set
+ for result in cursor.stored_results():
+ self.contInfo = result.fetchone()
+ except Error as e:
+ print(f"Error fetching contractor info: {e}")
finally:
- cursor.close()
- connection.close()
+ if connection.is_connected():
+ connection.close()
def fetchalldata(self):
-
+ """Fetch hold types and invoices for contractor."""
+ data = {}
try:
connection = config.get_db_connection()
- cursor = connection.cursor(dictionary=True, buffered=True)
- print("here", flush=True)
-
+ with connection.cursor(dictionary=True, buffered=True) as cursor:
+ # Fetch Hold Types
+ cursor.callproc('GetHoldTypesByContractor', [self.ID])
+ hold_types = []
+ for result in cursor.stored_results():
+ hold_types = result.fetchall()
+ hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types}
+ data['hold_types'] = hold_type_map
- # ---------------- Hold Types ----------------
- cursor = connection.cursor(dictionary=True)
+ # Fetch Invoices
+ cursor.callproc('GetInvoicesByContractor', [self.ID])
+ invoices = []
+ for result in cursor.stored_results():
+ invoices = result.fetchall()
- cursor.callproc('GetHoldTypesByContractor', [self.ID])
-
- hold_types = []
- for result in cursor.stored_results():
- hold_types = result.fetchall()
- hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types}
-
- # ---------------- Invoices ----------------
- cursor = connection.cursor(dictionary=True)
-
- cursor.callproc('GetInvoicesByContractor', [self.ID])
-
- invoices = []
- for result in cursor.stored_results():
- invoices = result.fetchall()
-
- # Remove duplicate invoices
- invoice_ids_seen = set()
- unique_invoices = []
- for inv in invoices:
- if inv["Invoice_Id"] not in invoice_ids_seen:
- invoice_ids_seen.add(inv["Invoice_Id"])
- unique_invoices.append(inv)
- invoices = unique_invoices
+ # Remove duplicate invoices
+ seen_ids = set()
+ unique_invoices = []
+ for inv in invoices:
+ if inv['Invoice_Id'] not in seen_ids:
+ seen_ids.add(inv['Invoice_Id'])
+ unique_invoices.append(inv)
+ data['invoices'] = unique_invoices
+ except Error as e:
+ print(f"Error fetching contractor data: {e}")
finally:
- cursor.close()
- connection.close()
+ if connection.is_connected():
+ connection.close()
-
+ return data
diff --git a/model/Invoice.py b/model/Invoice.py
index ac148ac..b002fb3 100644
--- a/model/Invoice.py
+++ b/model/Invoice.py
@@ -1,35 +1,76 @@
+
import config
import mysql.connector
-# ------------------- Helper -------------------
+# ------------------- Helper Functions -------------------
def clear_results(cursor):
+ """Consume all stored results to prevent cursor issues."""
for r in cursor.stored_results():
r.fetchall()
+def fetch_one(cursor):
+ """Fetch first row from stored results."""
+ for result in cursor.stored_results():
+ return result.fetchone()
+ return None
-# ------------------- Get Village Id -------------------
-def get_village_id(village_name):
+def fetch_all(cursor):
+ """Fetch all rows from stored results."""
+ data = []
+ for result in cursor.stored_results():
+ data.extend(result.fetchall())
+ return data
+
+def get_numeric_values(data):
+ """Return numeric fields for invoices safely."""
+ return [
+ float(data.get('basic_amount') or 0),
+ float(data.get('debit_amount') or 0),
+ float(data.get('after_debit_amount') or 0),
+ float(data.get('amount') or 0),
+ float(data.get('gst_amount') or 0),
+ float(data.get('tds_amount') or 0),
+ float(data.get('sd_amount') or 0),
+ float(data.get('on_commission') or 0),
+ float(data.get('hydro_testing') or 0),
+ float(data.get('gst_sd_amount') or 0),
+ float(data.get('final_amount') or 0),
+ ]
+
+def execute_db_operation(operation_func):
+ """General DB operation wrapper with commit/rollback."""
connection = config.get_db_connection()
cursor = connection.cursor(dictionary=True)
-
- cursor.callproc("GetVillageIdByName", (village_name,))
- village_result = None
-
- for rs in cursor.stored_results():
- village_result = rs.fetchone()
-
- cursor.close()
- connection.close()
- return village_result
-
-
-# ------------------- Insert Invoice -------------------
-def insert_invoice(data, village_id):
- connection = config.get_db_connection()
- cursor = connection.cursor(dictionary=True)
-
try:
- # 1. Insert Invoice
+ result = operation_func(cursor)
+ connection.commit()
+ return result
+ except Exception:
+ connection.rollback()
+ raise
+ finally:
+ cursor.close()
+ connection.close()
+
+
+# ------------------- Village Functions -------------------
+def get_village_id(village_name):
+ def operation(cursor):
+ cursor.callproc("GetVillageIdByName", (village_name,))
+ return fetch_one(cursor)
+ return execute_db_operation(operation)
+
+def get_all_villages():
+ def operation(cursor):
+ cursor.callproc("GetAllVillages")
+ return fetch_all(cursor)
+ return execute_db_operation(operation)
+
+
+# ------------------- Invoice Functions -------------------
+def insert_invoice(data, village_id):
+ def operation(cursor):
+ # Insert invoice
cursor.callproc('InsertInvoice', [
data.get('pmc_no'),
village_id,
@@ -37,29 +78,14 @@ def insert_invoice(data, village_id):
data.get('invoice_details'),
data.get('invoice_date'),
data.get('invoice_no'),
- float(data.get('basic_amount') or 0),
- float(data.get('debit_amount') or 0),
- float(data.get('after_debit_amount') or 0),
- float(data.get('amount') or 0),
- float(data.get('gst_amount') or 0),
- float(data.get('tds_amount') or 0),
- float(data.get('sd_amount') or 0),
- float(data.get('on_commission') or 0),
- float(data.get('hydro_testing') or 0),
- float(data.get('gst_sd_amount') or 0),
- float(data.get('final_amount') or 0)
+ *get_numeric_values(data)
])
-
- invoice_id = None
- for result in cursor.stored_results():
- row = result.fetchone()
- if row:
- invoice_id = row.get('invoice_id')
-
- if not invoice_id:
+ invoice_row = fetch_one(cursor)
+ if not invoice_row:
raise Exception("Invoice ID not returned")
+ invoice_id = invoice_row.get('invoice_id')
- # 2. Insert Inpayment
+ # Insert inpayment
cursor.callproc('InsertInpayment', [
data.get('pmc_no'),
village_id,
@@ -67,221 +93,41 @@ def insert_invoice(data, village_id):
data.get('invoice_details'),
data.get('invoice_date'),
data.get('invoice_no'),
- float(data.get('basic_amount') or 0),
- float(data.get('debit_amount') or 0),
- float(data.get('after_debit_amount') or 0),
- float(data.get('amount') or 0),
- float(data.get('gst_amount') or 0),
- float(data.get('tds_amount') or 0),
- float(data.get('sd_amount') or 0),
- float(data.get('on_commission') or 0),
- float(data.get('hydro_testing') or 0),
- float(data.get('gst_sd_amount') or 0),
- float(data.get('final_amount') or 0),
+ *get_numeric_values(data),
data.get('subcontractor_id')
])
clear_results(cursor)
-
- connection.commit()
return invoice_id
- except Exception as e:
- connection.rollback()
- raise e
+ return execute_db_operation(operation)
- finally:
- cursor.close()
- connection.close()
-
-
-# ------------------- Assign Subcontractor -------------------
-def assign_subcontractor(data, village_id):
- connection = config.get_db_connection()
- cursor = connection.cursor(dictionary=True)
-
- try:
- cursor.callproc('AssignSubcontractor', [
- data.get('pmc_no'),
- data.get('subcontractor_id'),
- village_id
- ])
- clear_results(cursor)
-
- connection.commit()
-
- except Exception as e:
- connection.rollback()
- raise e
-
- finally:
- cursor.close()
- connection.close()
-
-
-# ------------------- Insert Hold Types -------------------
-def insert_hold_types(data, invoice_id):
- connection = config.get_db_connection()
- cursor = connection.cursor(dictionary=True)
-
- try:
- hold_types = data.getlist('hold_type[]')
- hold_amounts = data.getlist('hold_amount[]')
-
- for hold_type, hold_amount in zip(hold_types, hold_amounts):
- if not hold_type:
- continue
-
- cursor.callproc('GetHoldTypeIdByName', [hold_type])
- hold_type_result = None
-
- for result in cursor.stored_results():
- hold_type_result = result.fetchone()
-
- if not hold_type_result:
- cursor.callproc('InsertHoldType', [hold_type, 0])
- cursor.execute("SELECT @_InsertHoldType_1")
- hold_type_id = cursor.fetchone()[0]
- else:
- hold_type_id = hold_type_result['hold_type_id']
-
- hold_amount = float(hold_amount or 0)
-
- cursor.callproc('InsertInvoiceSubcontractorHold', [
- data.get('subcontractor_id'),
- invoice_id,
- hold_type_id,
- hold_amount
- ])
- clear_results(cursor)
-
- connection.commit()
-
- except Exception as e:
- connection.rollback()
- raise e
-
- finally:
- cursor.close()
- connection.close()
-
-
-# ------------------- Get All Invoices -------------------
def get_all_invoice_details():
- connection = config.get_db_connection()
- cursor = connection.cursor(dictionary=True)
+ def operation(cursor):
+ cursor.callproc('GetAllInvoiceDetails')
+ return fetch_all(cursor)
+ return execute_db_operation(operation)
- cursor.callproc('GetAllInvoiceDetails')
- invoices = []
-
- for result in cursor.stored_results():
- invoices = result.fetchall()
-
- cursor.close()
- connection.close()
- return invoices
-
-
-# ------------------- Get All Villages -------------------
-def get_all_villages():
- connection = config.get_db_connection()
- cursor = connection.cursor(dictionary=True)
-
- cursor.callproc("GetAllVillages")
- villages = []
-
- for result in cursor.stored_results():
- villages = result.fetchall()
-
- cursor.close()
- connection.close()
- return villages
-
-
-# ------------------- Search Contractors -------------------
-def search_contractors(sub_query):
- connection = config.get_db_connection()
- cursor = connection.cursor(dictionary=True)
-
- cursor.callproc('SearchContractorsByName', [sub_query])
- results = []
-
- for result in cursor.stored_results():
- results = result.fetchall()
-
- cursor.close()
- connection.close()
- return results
-
-
-# ------------------- Get All Hold Types -------------------
-def get_all_hold_types():
- connection = config.get_db_connection()
- cursor = connection.cursor(dictionary=True)
-
- cursor.callproc("GetAllHoldTypes")
- hold_types = []
-
- for result in cursor.stored_results():
- hold_types = result.fetchall()
-
- cursor.close()
- connection.close()
- return hold_types
-
-
-# ------------------- Get Invoice By Id -------------------
def get_invoice_by_id(invoice_id):
- connection = config.get_db_connection()
- cursor = connection.cursor(dictionary=True)
+ def operation(cursor):
+ cursor.callproc('GetInvoiceDetailsById', [invoice_id])
+ invoice = fetch_one(cursor)
- cursor.callproc('GetInvoiceDetailsById', [invoice_id])
- invoice = None
+ cursor.callproc('GetHoldAmountsByInvoiceId', [invoice_id])
+ hold_amounts = fetch_all(cursor)
- for result in cursor.stored_results():
- invoice = result.fetchone()
+ if invoice:
+ invoice["hold_amounts"] = hold_amounts
+ return invoice
+ return execute_db_operation(operation)
- cursor.callproc('GetHoldAmountsByInvoiceId', [invoice_id])
- hold_amounts = []
-
- for result in cursor.stored_results():
- hold_amounts = result.fetchall()
-
- if invoice:
- invoice["hold_amounts"] = hold_amounts
-
- cursor.close()
- connection.close()
- return invoice
-
-
-# ------------------- Update Invoice -------------------
def update_invoice(data, invoice_id):
- connection = config.get_db_connection()
- cursor = connection.cursor(dictionary=True)
-
- try:
+ def operation(cursor):
cursor.callproc("GetVillageIdByName", (data.get('village'),))
- village = None
-
- for rs in cursor.stored_results():
- village = rs.fetchone()
-
+ village = fetch_one(cursor)
+ if not village:
+ raise Exception("Village not found")
village_id = village['Village_Id']
- numeric = [
- float(data.get('basic_amount') or 0),
- float(data.get('debit_amount') or 0),
- float(data.get('after_debit_amount') or 0),
- float(data.get('amount') or 0),
- float(data.get('gst_amount') or 0),
- float(data.get('tds_amount') or 0),
- float(data.get('sd_amount') or 0),
- float(data.get('on_commission') or 0),
- float(data.get('hydro_testing') or 0),
- float(data.get('gst_sd_amount') or 0),
- float(data.get('final_amount') or 0),
- ]
-
cursor.callproc('UpdateInvoice', [
data.get('pmc_no'),
village_id,
@@ -289,91 +135,101 @@ def update_invoice(data, invoice_id):
data.get('invoice_details'),
data.get('invoice_date'),
data.get('invoice_no'),
- *numeric,
+ *get_numeric_values(data),
invoice_id
])
clear_results(cursor)
+ execute_db_operation(operation)
- connection.commit()
-
- except Exception as e:
- connection.rollback()
- raise e
-
- finally:
- cursor.close()
- connection.close()
-
-
-# ------------------- Update Inpayment -------------------
def update_inpayment(data):
- connection = config.get_db_connection()
- cursor = connection.cursor(dictionary=True)
-
- try:
- numeric = [
- float(data.get('basic_amount') or 0),
- float(data.get('debit_amount') or 0),
- float(data.get('after_debit_amount') or 0),
- float(data.get('amount') or 0),
- float(data.get('gst_amount') or 0),
- float(data.get('tds_amount') or 0),
- float(data.get('sd_amount') or 0),
- float(data.get('on_commission') or 0),
- float(data.get('hydro_testing') or 0),
- float(data.get('gst_sd_amount') or 0),
- float(data.get('final_amount') or 0),
- ]
-
+ def operation(cursor):
cursor.callproc('UpdateInpayment', [
data.get('work_type'),
data.get('invoice_details'),
data.get('invoice_date'),
- *numeric,
+ *get_numeric_values(data),
data.get('pmc_no'),
data.get('invoice_no')
])
clear_results(cursor)
+ execute_db_operation(operation)
- connection.commit()
-
- except Exception as e:
- connection.rollback()
- raise e
-
- finally:
- cursor.close()
- connection.close()
-
-
-# ------------------- Delete Invoice -------------------
def delete_invoice_data(invoice_id, user_id):
- connection = config.get_db_connection()
- cursor = connection.cursor(dictionary=True)
-
- try:
- cursor.callproc('GetInvoicePMCById', [invoice_id])
-
+ def operation(cursor):
+ # Fetch PMC and Invoice_No from DB
+ cursor.callproc('GetInvoicePMCById', (invoice_id,))
record = {}
for result in cursor.stored_results():
record = result.fetchone() or {}
if not record:
raise Exception("Invoice not found")
+ # Use exact DB keys
+ pmc_no = record['PMC_No']
+ invoice_no = record['Invoice_No']
+
+ # Delete invoice
cursor.callproc("DeleteInvoice", (invoice_id,))
clear_results(cursor)
- cursor.callproc(
- 'DeleteInpaymentByPMCInvoice',
- [record['PMC_No'], record['invoice_no']]
- )
+ # Delete inpayment
+ cursor.callproc('DeleteInpaymentByPMCInvoice', (pmc_no, invoice_no))
+ clear_results(cursor)
- connection.commit()
+ execute_db_operation(operation)
- except Exception as e:
- connection.rollback()
- raise e
- finally:
- cursor.close()
- connection.close()
\ No newline at end of file
+# ------------------- Subcontractor Functions -------------------
+def assign_subcontractor(data, village_id):
+ def operation(cursor):
+ cursor.callproc('AssignSubcontractor', [
+ data.get('pmc_no'),
+ data.get('subcontractor_id'),
+ village_id
+ ])
+ clear_results(cursor)
+ execute_db_operation(operation)
+
+
+# ------------------- Hold Types Functions -------------------
+def insert_hold_types(data, invoice_id):
+ def operation(cursor):
+ hold_types = data.getlist('hold_type[]')
+ hold_amounts = data.getlist('hold_amount[]')
+
+ for hold_type, hold_amount in zip(hold_types, hold_amounts):
+ if not hold_type:
+ continue
+
+ cursor.callproc('GetHoldTypeIdByName', [hold_type])
+ hold_type_result = fetch_one(cursor)
+
+ if not hold_type_result:
+ cursor.callproc('InsertHoldType', [hold_type, 0])
+ cursor.execute("SELECT @_InsertHoldType_1")
+ hold_type_id = cursor.fetchone()[0]
+ else:
+ hold_type_id = hold_type_result['hold_type_id']
+
+ cursor.callproc('InsertInvoiceSubcontractorHold', [
+ data.get('subcontractor_id'),
+ invoice_id,
+ hold_type_id,
+ float(hold_amount or 0)
+ ])
+ clear_results(cursor)
+ execute_db_operation(operation)
+
+def get_all_hold_types():
+ def operation(cursor):
+ cursor.callproc("GetAllHoldTypes")
+ return fetch_all(cursor)
+ return execute_db_operation(operation)
+
+
+# ------------------- Contractor Functions -------------------
+def search_contractors(sub_query):
+ def operation(cursor):
+ cursor.callproc('SearchContractorsByName', [sub_query])
+ return fetch_all(cursor)
+ return execute_db_operation(operation)
\ No newline at end of file
diff --git a/model/ItemCRUD.py b/model/ItemCRUD.py
index 19f8dfb..db54bcc 100644
--- a/model/ItemCRUD.py
+++ b/model/ItemCRUD.py
@@ -21,8 +21,6 @@ class itemCRUDMapping:
self.name = "State"
elif itemType is ItemCRUDType.HoldType:
self.name = "Hold Type"
- elif itemType is ItemCRUDType.Subcontractor:
- self.name = "Subcontractor"
else:
self.name = "Item"
@@ -56,16 +54,12 @@ class ItemCRUD:
connection.commit()
self.isSuccess = True
- self.resultMessage = HtmlHelper.json_response(
- ResponseHandler.delete_success(self.itemCRUDMapping.name), 200
- )
+ self.resultMessage = ResponseHandler.delete_success(self.itemCRUDMapping.name)['message']
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
- )
+ self.resultMessage = ResponseHandler.delete_failure(self.itemCRUDMapping.name)['message']
finally:
cursor.close()
@@ -74,7 +68,7 @@ class ItemCRUD:
# ----------------------------------------------------------
# ADD
# ----------------------------------------------------------
- def AddItem(self, request, parentid=None, childname=None, storedprocfetch=None, storedprocadd=None, data=None):
+ def AddItem(self, request, parentid, childname, storedprocfetch, storedprocadd):
connection = config.get_db_connection()
if not connection:
@@ -88,70 +82,31 @@ class ItemCRUD:
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 '')}'"
+ f"User {current_user.id} adding '{childname}'"
)
+ # Validation
+ if not re.match(RegEx.patternAlphabetOnly, childname):
+ self.isSuccess = False
+ self.resultMessage = HtmlHelper.json_response(
+ ResponseHandler.invalid_name(self.itemCRUDMapping.name), 400
+ )
+ return
+
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
+ # Call check procedure
if parentid is None:
cursor.callproc(storedprocfetch, (childname,))
else:
cursor.callproc(storedprocfetch, (childname, parentid))
+ # ✅ FIX: initialize variable
existing_item = None
+
for rs in cursor.stored_results():
existing_item = rs.fetchone()
+ # Check duplicate
if existing_item:
self.isSuccess = False
self.resultMessage = HtmlHelper.json_response(
@@ -169,7 +124,6 @@ class ItemCRUD:
self.isSuccess = True
self.resultMessage = HtmlHelper.json_response(
-
ResponseHandler.add_success(self.itemCRUDMapping.name), 200
)
@@ -187,7 +141,7 @@ class ItemCRUD:
# ----------------------------------------------------------
# EDIT
# ----------------------------------------------------------
- def EditItem(self, request, childid, parentid=None, childname=None, storedprocupdate=None, data=None):
+ def EditItem(self, request, childid, parentid, childname, storedprocupdate):
connection = config.get_db_connection()
cursor = connection.cursor()
@@ -197,40 +151,12 @@ class ItemCRUD:
f"User {current_user.id} edited '{childid}'"
)
+ if not re.match(RegEx.patternAlphabetOnly, childname):
+ self.isSuccess = False
+ self.resultMessage = ResponseHandler.update_failure(self.itemCRUDMapping.name)['message']
+ return
+
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:
@@ -335,7 +261,9 @@ class ItemCRUD:
else:
cursor.callproc(storedprocfetch, (childname, parentid))
+ # ✅ FIX
existing_item = None
+
for rs in cursor.stored_results():
existing_item = rs.fetchone()
diff --git a/model/PmcReport.py b/model/PmcReport.py
index c8ec69e..40a35c3 100644
--- a/model/PmcReport.py
+++ b/model/PmcReport.py
@@ -1,12 +1,11 @@
+import os
import openpyxl
from openpyxl.styles import Font, PatternFill
+from decimal import Decimal
+from datetime import datetime
import config
from flask_login import current_user
from model.Log import LogHelper
-
-from model.Report import ReportHelper
-from model.FolderAndFile import FolderAndFile
-
class PmcReport:
@staticmethod
@@ -17,9 +16,8 @@ class PmcReport:
try:
- # cursor.callproc("GetContractorInfoByPmcNo", (pmc_no,))
- # pmc_info = next(cursor.stored_results()).fetchone()
- pmc_info = ReportHelper.execute_sp(cursor, 'GetContractorInfoByPmcNo', [pmc_no], True)
+ cursor.callproc("GetContractorInfoByPmcNo", (pmc_no,))
+ pmc_info = next(cursor.stored_results()).fetchone()
if not pmc_info:
return None
@@ -33,12 +31,15 @@ class PmcReport:
invoices = []
hold_amount_total = 0
if hold_type_ids:
+
hold_type_ids_str = ",".join(map(str, hold_type_ids))
+
cursor.callproc(
'GetInvoices_WithHold',
[pmc_no, pmc_info["Contractor_Id"], hold_type_ids_str]
)
else:
+
cursor.callproc(
'GetInvoices_NoHold',
[pmc_no, pmc_info["Contractor_Id"]]
@@ -53,42 +54,33 @@ class PmcReport:
# GST RELEASE
- # cursor.callproc('GetGSTReleaseByPMC', [pmc_no])
- # gst_rel = []
- # for result in cursor.stored_results():
- # gst_rel = result.fetchall()
-
- gst_rel = ReportHelper.execute_sp(cursor, 'GetGSTReleaseByPMC', [pmc_no])
+ cursor.callproc('GetGSTReleaseByPMC', [pmc_no])
+ gst_rel = []
+ for result in cursor.stored_results():
+ gst_rel = result.fetchall()
total_gst_basic = sum(row.get('basic_amount', 0) or 0 for row in gst_rel)
total_gst_final = sum(row.get('final_amount', 0) or 0 for row in gst_rel)
# ---------------- HOLD RELEASE ----------------
- # cursor.callproc('GetHoldReleaseByPMC', [pmc_no])
- # hold_release = []
- # for result in cursor.stored_results():
- # hold_release = result.fetchall()
+ cursor.callproc('GetHoldReleaseByPMC', [pmc_no])
+ hold_release = []
+ for result in cursor.stored_results():
+ hold_release = result.fetchall()
- hold_release = ReportHelper.execute_sp(cursor, 'GetHoldReleaseByPMC', [pmc_no])
# ---------------- CREDIT NOTE ----------------
- # cursor.callproc('GetCreditNoteByPMC', [pmc_no])
- # credit_note = []
- # for result in cursor.stored_results():
- # credit_note = result.fetchall()
-
- credit_note = ReportHelper.execute_sp(cursor, 'GetCreditNoteByPMC', [pmc_no])
-
- payments = ReportHelper.execute_sp(cursor, 'GetPaymentsByPMC', [pmc_no])
+ cursor.callproc('GetCreditNoteByPMC', [pmc_no])
+ credit_note = []
+ for result in cursor.stored_results():
+ credit_note = result.fetchall()
# ---------------- PAYMENTS ----------------
- # cursor.callproc('GetPaymentsByPMC', [pmc_no])
- # payments = []
- # for result in cursor.stored_results():
- # payments = result.fetchall()
-
-
+ cursor.callproc('GetPaymentsByPMC', [pmc_no])
+ payments = []
+ for result in cursor.stored_results():
+ payments = result.fetchall()
total_pay_amount = sum(row.get('Payment_Amount', 0) or 0 for row in payments)
total_pay_total = sum(row.get('Total_amount', 0) or 0 for row in payments)
@@ -133,73 +125,109 @@ class PmcReport:
def download_pmc_report(pmc_no):
connection = config.get_db_connection()
- if not connection:
- return None
+ output_folder = "static/download"
+ output_file = os.path.join(output_folder, f"PMC_Report_{pmc_no}.xlsx")
+
+ if not os.path.exists(output_folder):
+ os.makedirs(output_folder)
cursor = connection.cursor(dictionary=True)
try:
- # filename
- filename = f"PMC_Report_{pmc_no}.xlsx"
- output_folder = FolderAndFile.get_download_folder()
- output_file = FolderAndFile.get_download_path(filename)
-
- # ================= DATA FETCH =================
-
- contractor_info = ReportHelper.execute_sp(cursor, 'GetContractorDetailsByPMC', [pmc_no], "one")
+ cursor.callproc('GetContractorDetailsByPMC', [pmc_no])
+ contractor_info = next(cursor.stored_results()).fetchone()
if not contractor_info:
return None
- hold_types = ReportHelper.execute_sp(cursor, 'GetHoldTypesByContractor', [contractor_info["Contractor_Id"]])
+ cursor.callproc('GetHoldTypesByContractor', [contractor_info["Contractor_Id"]])
+ hold_types = next(cursor.stored_results()).fetchall()
hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types}
- invoices = ReportHelper.execute_sp(cursor, 'GetInvoicesAndGstReleaseByPmcNo', [pmc_no])
+ cursor.callproc('GetInvoicesAndGstReleaseByPmcNo', [pmc_no])
+ invoices = next(cursor.stored_results()).fetchall()
- credit_notes = ReportHelper.execute_sp(cursor, 'GetCreditNoteByContractor', [contractor_info["Contractor_Id"]])
+ cursor.callproc('GetCreditNoteByContractor',[contractor_info["Contractor_Id"]])
- hold_amounts = ReportHelper.execute_sp(cursor, 'GetHoldAmountsByContractor', [contractor_info["Contractor_Id"]])
+ credit_notes = []
+ for result in cursor.stored_results():
+ credit_notes = result.fetchall()
- all_payments = ReportHelper.execute_sp(cursor, 'GetAllPaymentsByPMC', [pmc_no])
+ credit_note_map = {}
+ for cn in credit_notes:
+ key = (cn["PMC_No"], cn["Invoice_No"])
+ credit_note_map.setdefault(key, []).append(cn)
- gst_releases = ReportHelper.execute_sp(cursor, 'GetGSTReleaseDetailsByPMC', [pmc_no])
-
- # ================= DATA MAPPING =================
+ cursor.callproc('GetHoldAmountsByContractor', [contractor_info["Contractor_Id"]])
+ hold_amounts = next(cursor.stored_results()).fetchall()
hold_data = {}
for h in hold_amounts:
hold_data.setdefault(h['Invoice_Id'], {})[h['hold_type_id']] = h['hold_amount']
+ cursor.callproc('GetAllPaymentsByPMC', [pmc_no])
+ all_payments = next(cursor.stored_results()).fetchall()
+
payments_map = {}
+ extra_payments = []
+
for pay in all_payments:
if pay['invoice_no']:
payments_map.setdefault(pay['invoice_no'], []).append(pay)
+ else:
+ extra_payments.append(pay)
+
+ # ---------------- GST RELEASE DETAILS ----------------
+ cursor.callproc('GetGSTReleaseDetailsByPMC', [pmc_no])
+
+ gst_releases = []
+ for result in cursor.stored_results():
+ gst_releases = result.fetchall()
+
+ gst_release_map = {}
+
+ for gr in gst_releases:
+
+ invoice_nos = []
+
+ if gr['Invoice_No']:
+
+ cleaned = gr['Invoice_No'].replace(' ', '')
+
+ if '&' in cleaned:
+ invoice_nos = cleaned.split('&')
+
+ elif ',' in cleaned:
+ invoice_nos = cleaned.split(',')
+
+ else:
+ invoice_nos = [cleaned]
+
+ for inv_no in invoice_nos:
+ gst_release_map.setdefault(inv_no, []).append(gr)
- # ================= LOG =================
LogHelper.log_action(
"Download PMC Report",
f"User {current_user.id} Download PMC Report '{pmc_no}'"
)
- # ================= EXCEL =================
workbook = openpyxl.Workbook()
sheet = workbook.active
sheet.title = "PMC Report"
- # HEADER INFO
sheet.append(["", "", "Laxmi Civil Engineering Services PVT. LTD."])
- sheet.append(["Contractor Name", contractor_info["Contractor_Name"]])
- sheet.append(["State", contractor_info["State_Name"]])
- sheet.append(["District", contractor_info["District_Name"]])
- sheet.append(["Block", contractor_info["Block_Name"]])
+ sheet.append(["Contractor Name", contractor_info["Contractor_Name"], "", "GST No", contractor_info["GST_No"], "", "GST Type", contractor_info["GST_Registration_Type"]])
+ sheet.append(["State", contractor_info["State_Name"], "", "PAN No", contractor_info["PAN_No"], "", "Address", contractor_info["Address"]])
+ sheet.append(["District", contractor_info["District_Name"], "", "Mobile No", contractor_info["Mobile_No"]])
+ sheet.append(["Block", contractor_info["Block_Name"], "", "Email", contractor_info["Email"]])
sheet.append([])
base_headers = [
"PMC No","Village","Work Type","Invoice Details","Invoice Date","Invoice No",
- "Basic Amount","Debit","After Debit Amount","GST","Amount","TDS",
- "SD","On Commission","Hydro Testing","GST SD Amount"
+ "Basic Amount","Debit","After Debit Amount","GST (18%)","Amount","TDS (1%)",
+ "SD (5%)","On Commission","Hydro Testing","GST SD Amount"
]
hold_headers = [ht['hold_type'] for ht in hold_types]
@@ -208,249 +236,58 @@ class PmcReport:
"Final Amount","Payment Amount","TDS Payment","Total Paid","UTR"
]
- headers = base_headers + hold_headers + payment_headers
- sheet.append(headers)
+ sheet.append(base_headers + hold_headers + payment_headers)
+
+ header_fill = PatternFill(start_color="ADD8E6",end_color="ADD8E6",fill_type="solid")
+ header_font = Font(bold=True)
- # STYLE
for cell in sheet[sheet.max_row]:
- cell.font = Font(bold=True)
+ cell.font = header_font
+ cell.fill = header_fill
- # DATA
seen_invoices = set()
+ processed_payments = set()
for inv in invoices:
invoice_no = inv["Invoice_No"]
payments = payments_map.get(invoice_no, [])
- if invoice_no in seen_invoices:
- continue
+ if invoice_no not in seen_invoices:
- seen_invoices.add(invoice_no)
+ seen_invoices.add(invoice_no)
+ first_payment = payments[0] if payments else None
- first_payment = payments[0] if payments else None
+ row = [
+ pmc_no, inv["Village_Name"], inv["Work_Type"],
+ inv["Invoice_Details"], inv["Invoice_Date"], invoice_no,
+ inv["Basic_Amount"], inv["Debit_Amount"],
+ inv["After_Debit_Amount"], inv["GST_Amount"],
+ inv["Amount"], inv["TDS_Amount"], inv["SD_Amount"],
+ inv["On_Commission"], inv["Hydro_Testing"], inv["GST_SD_Amount"]
+ ]
- row = [
- pmc_no,
- inv["Village_Name"],
- inv["Work_Type"],
- inv["Invoice_Details"],
- inv["Invoice_Date"],
- invoice_no,
- inv["Basic_Amount"],
- inv["Debit_Amount"],
- inv["After_Debit_Amount"],
- inv["GST_Amount"],
- inv["Amount"],
- inv["TDS_Amount"],
- inv["SD_Amount"],
- inv["On_Commission"],
- inv["Hydro_Testing"],
- inv["GST_SD_Amount"]
- ]
+ invoice_holds = hold_data.get(inv["Invoice_Id"], {})
- # HOLD DATA
- invoice_holds = hold_data.get(inv["Invoice_Id"], {})
- for ht_id in hold_type_map.keys():
- row.append(invoice_holds.get(ht_id, ""))
+ for ht_id in hold_type_map.keys():
+ row.append(invoice_holds.get(ht_id, ""))
- # PAYMENT DATA
- row += [
- inv["Final_Amount"],
- first_payment["Payment_Amount"] if first_payment else "",
- first_payment["TDS_Payment_Amount"] if first_payment else "",
- first_payment["Total_amount"] if first_payment else "",
- first_payment["UTR"] if first_payment else ""
- ]
+ row += [
+ inv["Final_Amount"],
+ first_payment["Payment_Amount"] if first_payment else "",
+ first_payment["TDS_Payment_Amount"] if first_payment else "",
+ first_payment["Total_amount"] if first_payment else "",
+ first_payment["UTR"] if first_payment else ""
+ ]
- sheet.append(row)
+ sheet.append(row)
- # AUTO WIDTH
- for col in sheet.columns:
- max_len = max((len(str(cell.value)) for cell in col if cell.value), default=0)
- sheet.column_dimensions[col[0].column_letter].width = max_len + 2
-
- # SAVE
workbook.save(output_file)
workbook.close()
- return output_folder, filename
-
- except Exception as e:
- print(f"Error generating PMC report: {e}")
- return None
+ return output_folder, f"PMC_Report_{pmc_no}.xlsx"
finally:
+
cursor.close()
- connection.close()
-
- # @staticmethod
- # def download_pmc_report(pmc_no):
-
- # connection = config.get_db_connection()
- # cursor = connection.cursor(dictionary=True)
-
- # # output_folder = "static/download"
- # # output_file = os.path.join(output_folder, f"PMC_Report_{pmc_no}.xlsx")
- # output_folder = FolderAndFile.get_download_folder
- # filename = f"PMC_Report_{pmc_no}.xlsx"
- # output_file = FolderAndFile.get_download_path(filename)
-
- # try:
-
- # cursor.callproc('GetContractorDetailsByPMC', [pmc_no])
- # contractor_info = next(cursor.stored_results()).fetchone()
-
- # if not contractor_info:
- # return None
-
- # cursor.callproc('GetHoldTypesByContractor', [contractor_info["Contractor_Id"]])
- # hold_types = next(cursor.stored_results()).fetchall()
-
- # hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types}
-
- # cursor.callproc('GetInvoicesAndGstReleaseByPmcNo', [pmc_no])
- # invoices = next(cursor.stored_results()).fetchall()
-
- # cursor.callproc('GetCreditNoteByContractor',[contractor_info["Contractor_Id"]])
-
- # credit_notes = []
- # for result in cursor.stored_results():
- # credit_notes = result.fetchall()
-
- # credit_note_map = {}
- # for cn in credit_notes:
- # key = (cn["PMC_No"], cn["Invoice_No"])
- # credit_note_map.setdefault(key, []).append(cn)
-
- # cursor.callproc('GetHoldAmountsByContractor', [contractor_info["Contractor_Id"]])
- # hold_amounts = next(cursor.stored_results()).fetchall()
-
- # hold_data = {}
- # for h in hold_amounts:
- # hold_data.setdefault(h['Invoice_Id'], {})[h['hold_type_id']] = h['hold_amount']
-
- # cursor.callproc('GetAllPaymentsByPMC', [pmc_no])
- # all_payments = next(cursor.stored_results()).fetchall()
-
- # payments_map = {}
- # extra_payments = []
-
- # for pay in all_payments:
- # if pay['invoice_no']:
- # payments_map.setdefault(pay['invoice_no'], []).append(pay)
- # else:
- # extra_payments.append(pay)
-
- # # ---------------- GST RELEASE DETAILS ----------------
- # cursor.callproc('GetGSTReleaseDetailsByPMC', [pmc_no])
-
- # gst_releases = []
- # for result in cursor.stored_results():
- # gst_releases = result.fetchall()
-
- # gst_release_map = {}
-
- # for gr in gst_releases:
-
- # invoice_nos = []
-
- # if gr['Invoice_No']:
-
- # cleaned = gr['Invoice_No'].replace(' ', '')
-
- # if '&' in cleaned:
- # invoice_nos = cleaned.split('&')
-
- # elif ',' in cleaned:
- # invoice_nos = cleaned.split(',')
-
- # else:
- # invoice_nos = [cleaned]
-
- # for inv_no in invoice_nos:
- # gst_release_map.setdefault(inv_no, []).append(gr)
-
- # LogHelper.log_action(
- # "Download PMC Report",
- # f"User {current_user.id} Download PMC Report '{pmc_no}'"
- # )
-
- # workbook = openpyxl.Workbook()
- # sheet = workbook.active
- # sheet.title = "PMC Report"
-
- # sheet.append(["", "", "Laxmi Civil Engineering Services PVT. LTD."])
- # sheet.append(["Contractor Name", contractor_info["Contractor_Name"], "", "GST No", contractor_info["GST_No"], "", "GST Type", contractor_info["GST_Registration_Type"]])
- # sheet.append(["State", contractor_info["State_Name"], "", "PAN No", contractor_info["PAN_No"], "", "Address", contractor_info["Address"]])
- # sheet.append(["District", contractor_info["District_Name"], "", "Mobile No", contractor_info["Mobile_No"]])
- # sheet.append(["Block", contractor_info["Block_Name"], "", "Email", contractor_info["Email"]])
- # sheet.append([])
-
- # base_headers = [
- # "PMC No","Village","Work Type","Invoice Details","Invoice Date","Invoice No",
- # "Basic Amount","Debit","After Debit Amount","GST (18%)","Amount","TDS (1%)",
- # "SD (5%)","On Commission","Hydro Testing","GST SD Amount"
- # ]
-
- # hold_headers = [ht['hold_type'] for ht in hold_types]
-
- # payment_headers = [
- # "Final Amount","Payment Amount","TDS Payment","Total Paid","UTR"
- # ]
-
- # sheet.append(base_headers + hold_headers + payment_headers)
-
- # header_fill = PatternFill(start_color="ADD8E6",end_color="ADD8E6",fill_type="solid")
- # header_font = Font(bold=True)
-
- # for cell in sheet[sheet.max_row]:
- # cell.font = header_font
- # cell.fill = header_fill
-
- # seen_invoices = set()
- # processed_payments = set()
-
- # for inv in invoices:
-
- # invoice_no = inv["Invoice_No"]
- # payments = payments_map.get(invoice_no, [])
-
- # if invoice_no not in seen_invoices:
-
- # seen_invoices.add(invoice_no)
- # first_payment = payments[0] if payments else None
-
- # row = [
- # pmc_no, inv["Village_Name"], inv["Work_Type"],
- # inv["Invoice_Details"], inv["Invoice_Date"], invoice_no,
- # inv["Basic_Amount"], inv["Debit_Amount"],
- # inv["After_Debit_Amount"], inv["GST_Amount"],
- # inv["Amount"], inv["TDS_Amount"], inv["SD_Amount"],
- # inv["On_Commission"], inv["Hydro_Testing"], inv["GST_SD_Amount"]
- # ]
-
- # invoice_holds = hold_data.get(inv["Invoice_Id"], {})
-
- # for ht_id in hold_type_map.keys():
- # row.append(invoice_holds.get(ht_id, ""))
-
- # row += [
- # inv["Final_Amount"],
- # first_payment["Payment_Amount"] if first_payment else "",
- # first_payment["TDS_Payment_Amount"] if first_payment else "",
- # first_payment["Total_amount"] if first_payment else "",
- # first_payment["UTR"] if first_payment else ""
- # ]
-
- # sheet.append(row)
-
- # workbook.save(output_file)
- # workbook.close()
-
- # return output_folder, filename
-
- # finally:
-
- # cursor.close()
- # connection.close()
\ No newline at end of file
+ connection.close()
\ No newline at end of file
diff --git a/model/Report.py b/model/Report.py
index 41d5ad2..433be6e 100644
--- a/model/Report.py
+++ b/model/Report.py
@@ -1,110 +1,78 @@
import config
from datetime import datetime
-from flask import send_file
-import openpyxl
-from openpyxl.styles import Font
-
-from model.FolderAndFile import FolderAndFile
class ReportHelper:
- isSuccess = False
- resultMessage = ""
- data=[]
-
- def __init__(self):
- self.isSuccess = False
- self.resultMessage = ""
- self.data = []
@staticmethod
- def execute_sp(cursor, proc_name, params=[], fetch_one=False):
- cursor.callproc(proc_name, params)
- return (
- ReportHelper.fetch_one_result(cursor)
- if fetch_one else
- ReportHelper.fetch_all_results(cursor)
- )
+ def search_contractor(subcontractor_name, pmc_no, state, district, block, village, year_from, year_to):
+
+ connection = config.get_db_connection()
+ cursor = connection.cursor(dictionary=True)
+
+ cursor.callproc("search_contractor_info", [
+ subcontractor_name or None,
+ pmc_no or None,
+ state or None,
+ district or None,
+ block or None,
+ village or None,
+ year_from or None,
+ year_to or None
+ ])
- @staticmethod
- def fetch_all_results(cursor):
data = []
for result in cursor.stored_results():
data = result.fetchall()
- return data
-
- @staticmethod
- def fetch_one_result(cursor):
- data = None
- for result in cursor.stored_results():
- data = result.fetchone()
- return data
-
-
- @staticmethod
- def search_contractor(request):
- subcontractor_name = request.form.get("subcontractor_name")
- pmc_no = request.form.get("pmc_no")
- state = request.form.get("state")
- district = request.form.get("district")
- block = request.form.get("block")
- village = request.form.get("village")
- year_from = request.form.get("year_from")
- year_to = request.form.get("year_to")
-
- connection = config.get_db_connection()
- if not connection:
- return []
-
- cursor = connection.cursor(dictionary=True)
-
- try:
- data = ReportHelper.execute_sp(
- cursor,
- "search_contractor_info",
- [
- subcontractor_name or None,
- pmc_no or None,
- state or None,
- district or None,
- block or None,
- village or None,
- year_from or None,
- year_to or None
- ]
- )
-
- except Exception as e:
- print(f"Error in search_contractor: {e}")
- data = []
-
- finally:
- cursor.close()
- connection.close()
+ cursor.close()
+ connection.close()
return data
@staticmethod
def get_contractor_report(contractor_id):
+
connection = config.get_db_connection()
cursor = connection.cursor(dictionary=True, buffered=True)
-
+
+
try:
- # Contractor Info (only one fetch)
- contInfo = ReportHelper.execute_sp(cursor, 'GetContractorInfo', [contractor_id], True)
+ # Contractor Info
+ cursor.callproc('GetContractorInfo', [contractor_id])
+ for result in cursor.stored_results():
+ contInfo = result.fetchone()
+
# Hold Types
- hold_types = ReportHelper.execute_sp(cursor, 'GetContractorHoldTypes', [contractor_id])
+ cursor.callproc('GetContractorHoldTypes', [contractor_id])
+ for result in cursor.stored_results():
+ hold_types = result.fetchall()
+
# Invoices
- invoices = ReportHelper.execute_sp(cursor, 'GetContractorInvoices', [contractor_id])
+ cursor.callproc('GetContractorInvoices', [contractor_id])
+ for result in cursor.stored_results():
+ invoices = result.fetchall()
+
# GST Release
- gst_rel = ReportHelper.execute_sp(cursor, 'GetGSTRelease', [contractor_id])
+ cursor.callproc('GetGSTRelease', [contractor_id])
+ for result in cursor.stored_results():
+ gst_rel = result.fetchall()
+
# Hold Release
- hold_release = ReportHelper.execute_sp(cursor, 'GetHoldRelease', [contractor_id])
+ cursor.callproc('GetHoldRelease', [contractor_id])
+ for result in cursor.stored_results():
+ hold_release = result.fetchall()
+
# Credit Note
- credit_note = ReportHelper.execute_sp(cursor, 'GetCreditNote', [contractor_id])
+ cursor.callproc('GetCreditNote', [contractor_id])
+ for result in cursor.stored_results():
+ credit_note = result.fetchall()
+
# Payments
- payments = ReportHelper.execute_sp(cursor, 'GetPayments', [contractor_id])
+ cursor.callproc('GetPayments', [contractor_id])
+ for result in cursor.stored_results():
+ payments = result.fetchall()
+
# Totals
total = {
@@ -146,130 +114,3 @@ class ReportHelper:
"total": total,
"current_date": current_date
}
-
- @staticmethod
- def download_report(contractor_id):
- try:
- connection = config.get_db_connection()
- cursor = connection.cursor(dictionary=True)
-
- # -------- Contractor Info --------
- contInfo = ReportHelper.execute_sp(cursor, 'GetContractorInfo', [contractor_id], True)
-
- 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 =================
- 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)
\ No newline at end of file
diff --git a/model/ReportGenerator.py b/model/ReportGenerator.py
new file mode 100644
index 0000000..e69de29
diff --git a/model/State.py b/model/State.py
index 9245a99..a088c2e 100644
--- a/model/State.py
+++ b/model/State.py
@@ -1,168 +1,246 @@
-from flask import request, redirect, url_for
-from flask_login import current_user
+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 model.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType
-from model.Log import LogHelper
-from model.ItemCRUD import ItemCRUD
+from model.Log import LogData, LogHelper
+import os
import config
import re
-import mysql.connector
+import mysql.connector
+from mysql.connector import Error
class State:
+ isSuccess = False
+ resultMessage = ""
+
def __init__(self):
self.isSuccess = False
self.resultMessage = ""
- # ----------------------------------------------------------
- # ADD STATE (USING ITEM CRUD)
- # ----------------------------------------------------------
def AddState(self, request):
-
- state_name = request.form['state_Name'].strip()
-
- crud = ItemCRUD(ItemCRUDType.State)
-
- crud.AddItem(
- request=request,
- childname=state_name,
- storedprocfetch="CheckStateExists",
- storedprocadd="SaveState"
- )
-
- self.isSuccess = crud.isSuccess
- self.resultMessage = crud.resultMessage
-
- return self.resultMessage
-
-
- # ----------------------------------------------------------
- # GET ALL STATES (NO CHANGE - THIS IS CORRECT)
- # ----------------------------------------------------------
- def GetAllStates(self, request):
-
+ """Log user actions with timestamp, user, action, and details."""
+ statedata = []
+
connection = config.get_db_connection()
- data = []
+
+ if connection:
+ cursor = connection.cursor()
+ state_name = request.form['state_Name'].strip()
+ LogHelper.log_action("Add State", f"User {current_user.id} added state '{state_name}'")
+
+ if not re.match(RegEx.patternAlphabetOnly, state_name):
+ self.isSuccess = False
+ self.resultMessage = HtmlHelper.json_response(ResponseHandler.invalid_name("state"), 400)
+ return
+
+ try:
+
+ cursor.callproc("CheckStateExists", (state_name,))
+ for data in cursor.stored_results():
+ existing_state = data.fetchone()
+
+ if existing_state:
+ self.isSuccess = False
+ self.resultMessage = HtmlHelper.json_response(ResponseHandler.already_exists("state"), 409)
+ return
+
+ # cursor.execute("call SaveState (%s)", (state_name,))
+ cursor.callproc("SaveState", (state_name,))
+ connection.commit()
+ self.isSuccess = True
+ self.resultMessage = HtmlHelper.json_response(ResponseHandler.add_success("state"), 200)
+ return
+
+ except mysql.connector.Error as e:
+ print(f"Error inserting state: {e}")
+ self.isSuccess = False
+ self.resultMessage = HtmlHelper.json_response(ResponseHandler.add_failure("state"), 500)
+ return
+
+ #Need to make this seperate
+
+
+
+ def GetAllStates(self, request):
+ """Log user actions with timestamp, user, action, and details."""
+ statedata = []
+ connection = config.get_db_connection()
+
+ self.isSuccess = False
+ self.resultMessage = ""
if not connection:
return []
-
+
cursor = connection.cursor()
try:
cursor.callproc("GetAllStates")
for res in cursor.stored_results():
- data = res.fetchall()
-
+ statedata = res.fetchall()
self.isSuccess = True
+
except mysql.connector.Error as e:
print(f"Error fetching states: {e}")
self.isSuccess = False
- self.resultMessage = HtmlHelper.json_response(
- ResponseHandler.fetch_failure("state"), 500
- )
- return []
+ self.resultMessage = HtmlHelper.json_response(ResponseHandler.fetch_failure("state"), 500)
+ return []
finally:
cursor.close()
connection.close()
- return data
+ return statedata
+
- # ----------------------------------------------------------
- # CHECK STATE (USING ITEM CRUD)
- # ----------------------------------------------------------
def CheckState(self, request):
-
- state_name = request.json.get('state_Name', '').strip()
-
- crud = ItemCRUD(ItemCRUDType.State)
-
- return crud.CheckItem(
- request=request,
- parentid=None,
- childname=state_name,
- storedprocfetch="CheckStateExists"
- )
-
-
- # ----------------------------------------------------------
- # DELETE STATE (USING ITEM CRUD)
- # ----------------------------------------------------------
- def DeleteState(self, request, id):
-
- crud = ItemCRUD(ItemCRUDType.State)
-
- crud.DeleteItem(
- request=request,
- itemID=id,
- storedprocDelete="DeleteState"
- )
-
- self.isSuccess = crud.isSuccess
- self.resultMessage = crud.resultMessage
-
- return self.resultMessage
-
-
- # ----------------------------------------------------------
- # EDIT STATE (USING ITEM CRUD)
- # ----------------------------------------------------------
- def EditState(self, request, id):
-
- state_name = request.form['state_Name'].strip()
-
- crud = ItemCRUD(ItemCRUDType.State)
-
- crud.EditItem(
- request=request,
- childid=id,
- parentid=None,
- childname=state_name,
- storedprocupdate="UpdateStateById"
- )
-
- self.isSuccess = crud.isSuccess
- self.resultMessage = crud.resultMessage
-
- return redirect(url_for('state.add_state'))
-
-
- # ----------------------------------------------------------
- # GET STATE BY ID (KEEP SAME)
- # ----------------------------------------------------------
- def GetStateByID(self, request, id):
+ self.isSuccess = False
+ self.resultMessage = ""
connection = config.get_db_connection()
- data = None
+ #connection closing needs to be verified
+ if connection:
+ cursor = connection.cursor()
+ state_name = request.json.get('state_Name', '').strip()
+ LogHelper.log_action("Check State", f"User {current_user.id} Checked state '{state_name}'")
+ if not re.match(RegEx.patternAlphabetOnly, state_name):
+ self.isSuccess = False
+ self.resultMessage = HtmlHelper.json_response(ResponseHandler.invalid_name("state"), 400)
+ return HtmlHelper.json_response(ResponseHandler.invalid_name("state"), 400)
+ try:
+ # cursor.execute("SELECT * FROM states WHERE State_Name = %s", (state_name,))
+ # existing_state = cursor.fetchone()
+
+ cursor.callproc("CheckStateExists", (state_name,))
+ for data in cursor.stored_results():
+ existing_state = data.fetchone()
+
+ if existing_state:
+ self.isSuccess = False
+ self.resultMessage = HtmlHelper.json_response(ResponseHandler.already_exists("state"), 409)
+ return HtmlHelper.json_response(ResponseHandler.already_exists("state"), 409)
+ else:
+ self.isSuccess = True
+ self.resultMessage = HtmlHelper.json_response(ResponseHandler.is_available("state"), 200)
+ return HtmlHelper.json_response(ResponseHandler.is_available("state"), 200)
+
+ except mysql.connector.Error as e:
+ self.isSuccess = False
+ self.resultMessage = HtmlHelper.json_response(ResponseHandler.add_failure("state"), 500)
+
+ print(f"Error checking state: {e}")
+ return HtmlHelper.json_response(ResponseHandler.add_failure("state"), 500)
+ finally:
+ cursor.close()
+ connection.close()
+
+
+
+ def DeleteState(self, request, id):
+ self.isSuccess = False
+ self.resultMessage = ""
+
+ connection = config.get_db_connection()
+ cursor = connection.cursor()
+ LogHelper.log_action("Delete State", f"User {current_user.id} Deleted state '{id}'")
+ try:
+ cursor.callproc('DeleteState', (id,))
+ connection.commit()
+
+ self.resultMessage = "Successfully Deleted"
+ self.isSuccess = True
+ except mysql.connector.Error as e:
+ print(f"Error deleting data: {e}")
+ self.isSuccess = False
+ self.resultMessage = HtmlHelper.json_response(ResponseHandler.delete_failure("state"), 500)
+ return HtmlHelper.json_response(ResponseHandler.delete_failure("state"), 500)
+
+ finally:
+ cursor.close()
+ connection.close()
+ return self.resultMessage
+
+
+ def EditState(self, request, id):
+ self.isSuccess = False
+ self.resultMessage = ""
+
+ connection = config.get_db_connection()
+ cursor = connection.cursor()
+ # str_pattern_reg = r"^[A-Za-z\s]+$"
+
+ state_name = request.form['state_Name'].strip()
+ LogHelper.log_action("Edit State", f"User {current_user.id} Edited state '{state_name}'")
+ if not re.match(RegEx.patternAlphabetOnly, state_name):
+ self.isSuccess = False
+ self.resultMessage = ResponseHandler.invalid_name("state"), 400
+ return ResponseHandler.invalid_name("state"), 400
+
+ try:
+ # cursor.execute("UPDATE states SET State_Name = %s WHERE State_ID = %s", (state_name, id))
+ cursor.callproc("UpdateStateById", (id, state_name))
+ connection.commit()
+ self.isSuccess = True
+ self.resultMessage = "Successfully Edited"
+ return redirect(url_for('state.add_state'))
+ except mysql.connector.Error as e:
+ print(f"Error updating data: {e}")
+ self.isSuccess = True
+ self.resultMessage = ResponseHandler.add_failure("state"), 500
+
+ return ResponseHandler.add_failure("state"), 500
+ finally:
+ cursor.close()
+ connection.close()
+
+
+
+
+
+ def GetStateByID(self, request, id):
+ """Log user actions with timestamp, user, action, and details."""
+ statedata = []
+
+ self.isSuccess = False
+ self.resultMessage = ""
+
+ connection = config.get_db_connection()
if not connection:
- return None
-
+ return []
cursor = connection.cursor()
try:
cursor.callproc("GetStateByID", (id,))
for res in cursor.stored_results():
- data = res.fetchone()
+ statedata = res.fetchone()
- if data:
+ if statedata:
self.isSuccess = True
- self.resultMessage = "Success"
+ self.resultMessage = "Success in Fetching"
else:
self.isSuccess = False
- self.resultMessage = "Not Found"
+ self.resultMessage = "State Not Found"
+
except mysql.connector.Error as e:
- print(f"Error fetching state: {e}")
+ print(f"Error fetching states: {e}")
self.isSuccess = False
+ self.resultMessage = HtmlHelper.json_response(ResponseHandler.fetch_failure("state"), 500)
+ return []
finally:
cursor.close()
connection.close()
- return data
\ No newline at end of file
+ return statedata
+
+
diff --git a/model/Subcontractor.py b/model/Subcontractor.py
index 0ec659d..7556642 100644
--- a/model/Subcontractor.py
+++ b/model/Subcontractor.py
@@ -1,140 +1,131 @@
-from model.Utilities import ItemCRUDType
-from model.ItemCRUD import ItemCRUD
+# model/Subcontractor.py
+import config
+from model.Log import LogHelper
+from mysql.connector import Error
class Subcontractor:
- def __init__(self):
- self.isSuccess = False
- self.resultMessage = ""
- # ----------------------------------------------------------
- # ADD
- # ----------------------------------------------------------
- def AddSubcontractor(self, request):
+ @staticmethod
+ def get_connection():
+ return config.get_db_connection()
- subcontractor = ItemCRUD(itemType=ItemCRUDType.Subcontractor)
+ @staticmethod
+ def get_all_subcontractors():
+ connection = Subcontractor.get_connection()
+ subcontractors = []
+ if not connection:
+ return None, "Database connection failed"
+ try:
+ cursor = connection.cursor()
+ cursor.callproc('GetAllSubcontractors')
+ for result in cursor.stored_results():
+ subcontractors = result.fetchall()
+ except Error as e:
+ print(f"Error fetching subcontractors: {e}")
+ return None, str(e)
+ finally:
+ cursor.close()
+ connection.close()
+ return subcontractors, None
- data = {
- "Contractor_Name": request.form.get('Contractor_Name', '').strip(),
- "Address": request.form.get('Address', '').strip(),
- "Mobile_No": request.form.get('Mobile_No', '').strip(),
- "PAN_No": request.form.get('PAN_No', '').strip(),
- "Email": request.form.get('Email', '').strip(),
- "Gender": request.form.get('Gender', '').strip(),
- "GST_Registration_Type": request.form.get('GST_Registration_Type', '').strip(),
- "GST_No": request.form.get('GST_No', '').strip(),
- "Contractor_password": request.form.get('Contractor_password', '').strip()
- }
+ @staticmethod
+ def get_subcontractor_by_id(id):
+ connection = Subcontractor.get_connection()
+ subcontractor = None
+ if not connection:
+ return None, "Database connection failed"
+ try:
+ cursor = connection.cursor()
+ cursor.callproc("GetSubcontractorById", (id,))
+ for result in cursor.stored_results():
+ subcontractor = result.fetchone()
+ except Error as e:
+ print(f"Error fetching subcontractor: {e}")
+ return None, str(e)
+ finally:
+ cursor.close()
+ connection.close()
+ return subcontractor, None
- subcontractor.AddItem(
- request=request,
- data=data,
- storedprocfetch="GetSubcontractorByName",
- storedprocadd="SaveContractor"
- )
+ @staticmethod
+ def save_subcontractor(data):
+ connection = Subcontractor.get_connection()
+ if not connection:
+ return "Database connection failed"
+ try:
+ cursor = connection.cursor()
+ cursor.callproc('SaveContractor', (
+ 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()
+ # Active log
+ LogHelper.log_action("Add Subcontractor", f"Added subcontractor '{data['Contractor_Name']}'")
+ except Error as e:
+ print(f"Error inserting subcontractor: {e}")
+ return str(e)
+ finally:
+ cursor.close()
+ connection.close()
+ return None
- self.isSuccess = subcontractor.isSuccess
- self.resultMessage = subcontractor.resultMessage
- return
+ @staticmethod
+ def update_subcontractor(id, data):
+ connection = Subcontractor.get_connection()
+ if not connection:
+ return "Database connection failed"
+ try:
+ cursor = connection.cursor()
+ cursor.callproc('UpdateSubcontractor', (
+ id,
+ 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()
+ # Active log
+ LogHelper.log_action("Edit Subcontractor", f"Edited subcontractor '{id}'")
+ except Error as e:
+ print(f"Error updating subcontractor: {e}")
+ return str(e)
+ finally:
+ cursor.close()
+ connection.close()
+ return None
- # ----------------------------------------------------------
- # GET ALL
- # ----------------------------------------------------------
- def GetAllSubcontractors(self, request):
-
- subcontractor = ItemCRUD(itemType=ItemCRUDType.Subcontractor)
-
- data = subcontractor.GetAllData(
- request=request,
- storedproc="GetAllSubcontractors"
- )
-
- self.isSuccess = subcontractor.isSuccess
- self.resultMessage = subcontractor.resultMessage
- return data
-
- # ----------------------------------------------------------
- # GET BY ID
- # ----------------------------------------------------------
- def GetSubcontractorByID(self, id):
-
- subcontractor = ItemCRUD(itemType=ItemCRUDType.Subcontractor)
-
- data = subcontractor.GetDataByID(
- id=id,
- storedproc="GetSubcontractorById"
- )
-
- if data:
- self.isSuccess = True
- else:
- self.isSuccess = False
- self.resultMessage = "Subcontractor not found"
-
- return data
-
- # ----------------------------------------------------------
- # CHECK (Duplicate)
- # ----------------------------------------------------------
- def CheckSubcontractor(self, request):
-
- subcontractor = ItemCRUD(itemType=ItemCRUDType.Subcontractor)
-
- name = request.form.get('Contractor_Name', '').strip()
-
- result = subcontractor.CheckItem(
- request=request,
- childname=name,
- storedprocfetch="GetSubcontractorByName"
- )
-
- self.isSuccess = subcontractor.isSuccess
- self.resultMessage = subcontractor.resultMessage
- return result
-
- # ----------------------------------------------------------
- # EDIT
- # ----------------------------------------------------------
- def EditSubcontractor(self, request, subcontractor_id):
-
- subcontractor = ItemCRUD(itemType=ItemCRUDType.Subcontractor)
-
- data = {
- "Contractor_Name": request.form.get('Contractor_Name', '').strip(),
- "Address": request.form.get('Address', '').strip(),
- "Mobile_No": request.form.get('Mobile_No', '').strip(),
- "PAN_No": request.form.get('PAN_No', '').strip(),
- "Email": request.form.get('Email', '').strip(),
- "Gender": request.form.get('Gender', '').strip(),
- "GST_Registration_Type": request.form.get('GST_Registration_Type', '').strip(),
- "GST_No": request.form.get('GST_No', '').strip(),
- "Contractor_password": request.form.get('Contractor_password', '').strip()
- }
-
- subcontractor.EditItem(
- request=request,
- childid=subcontractor_id,
- data=data,
- storedprocupdate="UpdateSubcontractor"
- )
-
- self.isSuccess = subcontractor.isSuccess
- self.resultMessage = subcontractor.resultMessage
- return
-
- # ----------------------------------------------------------
- # DELETE
- # ----------------------------------------------------------
- def DeleteSubcontractor(self, request, subcontractor_id):
-
- subcontractor = ItemCRUD(itemType=ItemCRUDType.Subcontractor)
-
- subcontractor.DeleteItem(
- request=request,
- itemID=subcontractor_id,
- storedprocDelete="DeleteSubcontractor"
- )
-
- self.isSuccess = subcontractor.isSuccess
- self.resultMessage = subcontractor.resultMessage
- return
\ No newline at end of file
+ @staticmethod
+ def delete_subcontractor(id):
+ connection = Subcontractor.get_connection()
+ if not connection:
+ return "Database connection failed", 0
+ affected_rows = 0
+ try:
+ cursor = connection.cursor()
+ cursor.callproc('DeleteSubcontractor', (id,))
+ connection.commit()
+ for result in cursor.stored_results():
+ row = result.fetchone()
+ affected_rows = row[0] if row else 0
+ # Active log
+ LogHelper.log_action("Delete Subcontractor", f"Deleted subcontractor '{id}'")
+ except Error as e:
+ print(f"Error deleting subcontractor: {e}")
+ return str(e), 0
+ finally:
+ cursor.close()
+ connection.close()
+ return None, affected_rows
\ No newline at end of file
diff --git a/model/Utilities.py b/model/Utilities.py
index 83868ba..d35827f 100644
--- a/model/Utilities.py
+++ b/model/Utilities.py
@@ -7,8 +7,6 @@ class ItemCRUDType(Enum):
District = 3
State = 4
HoldType = 5
- Subcontractor = 6
-
class RegEx:
patternAlphabetOnly = "^[A-Za-z ]+$"
diff --git a/model/Village.py b/model/Village.py
index 3b7b0cb..fa5b9bd 100644
--- a/model/Village.py
+++ b/model/Village.py
@@ -1,14 +1,7 @@
-
-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
-
+# return blocks
+from model.Utilities import ResponseHandler, HtmlHelper, ItemCRUDType
import config
-
import mysql.connector
-from mysql.connector import Error
-
from model.ItemCRUD import ItemCRUD
@@ -19,103 +12,162 @@ class Village:
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):
- village = ItemCRUD(itemType=ItemCRUDType.Village)
+ block_id, village_name = self._get_form_data(request)
- block_id = request.form.get('block_Id')
- village_name = request.form.get('Village_Name', '').strip()
+ if not village_name:
+ self.isSuccess = False
+ self.resultMessage = "Village name cannot be empty"
+ return
- village.AddItem(request=request, parentid=block_id, childname=village_name, storedprocfetch="GetVillageByNameAndBlock", storedprocadd="SaveVillage" )
- self.isSuccess = village.isSuccess
- self.resultMessage = village.resultMessage
- return
- #self.isSuccess = False
+ 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):
- village = ItemCRUD(itemType=ItemCRUDType.Village)
- villagesdata = village.GetAllData(request=request, storedproc="GetAllVillages")
- self.isSuccess = village.isSuccess
- self.resultMessage = village.resultMessage
- return villagesdata
+ try:
+ villagesdata = self.village.GetAllData(
+ request=request,
+ storedproc="GetAllVillages"
+ )
+ self._set_status(self.village)
+ return villagesdata
+
+ except Exception as e:
+ self.isSuccess = False
+ self.resultMessage = str(e)
+ return []
def CheckVillage(self, request):
- village = ItemCRUD(itemType=ItemCRUDType.Village)
- block_id = request.form.get('block_Id')
- village_name = request.form.get('Village_Name', '').strip()
- result = village.CheckItem(request=request, parentid=block_id, childname=village_name, storedprocfetch="GetVillageByNameAndBlocks")
- self.isSuccess = village.isSuccess
- self.resultMessage = village.resultMessage
- return result
+ 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):
- village = ItemCRUD(itemType=ItemCRUDType.Village)
+ try:
+ self.village.DeleteItem(
+ request=request,
+ itemID=village_id,
+ storedprocDelete="DeleteVillage"
+ )
+ self._set_status(self.village)
- village.DeleteItem(request=request, itemID=village_id, storedprocDelete="DeleteVillage" )
- self.isSuccess = village.isSuccess
- self.resultMessage = village.resultMessage
- return
+ except Exception as e:
+ self.isSuccess = False
+ self.resultMessage = str(e)
def EditVillage(self, request, village_id):
- corsor=None
- village = ItemCRUD(itemType=ItemCRUDType.Village)
+ block_id, village_name = self._get_form_data(request)
- block_id = request.form.get('block_Id')
- village_name = request.form.get('Village_Name', '').strip()
-
- village.EditItem(request=request,childid=village_id,parentid=block_id,childname=village_name,storedprocupdate="UpdateVillage" )
-
- self.isSuccess = village.isSuccess
- self.resultMessage = village.resultMessage
- return
-
- # def GetVillageByID(self, request, id):
-
- # village = ItemCRUD(itemType=ItemCRUDType.Village)
- # villagedetailsdata = village.GetAllData(request=request, storedproc="GetVillageDetailsById")
- # self.isSuccess = village.isSuccess
- # self.resultMessage = village.resultMessage
- # return villagedetailsdata
-
- def GetVillageByID(self, request, id):
- village = ItemCRUD(itemType=ItemCRUDType.Village)
- villagedetailsdata = village.GetDataByID(id=id,storedproc="GetVillageDetailsById")
- if villagedetailsdata:
- self.isSuccess = True
- else:
+ if not village_name:
self.isSuccess = False
- self.resultMessage = "Village not found"
+ self.resultMessage = "Village name cannot be empty"
+ return
- return villagedetailsdata
+ try:
+ self.village.EditItem(
+ request=request,
+ childid=village_id,
+ parentid=block_id,
+ childname=village_name,
+ storedprocupdate="UpdateVillage"
+ )
+ self._set_status(self.village)
+ except Exception as e:
+ self.isSuccess = False
+ self.resultMessage = str(e)
- def GetAllBlocks(self, request):
+ def GetVillageByID(self, id):
+ try:
+ villagedetailsdata = self.village.GetDataByID(
+ id=id,
+ storedproc="GetVillageDetailsById"
+ )
+
+ if villagedetailsdata:
+ self.isSuccess = True
+ else:
+ self.isSuccess = False
+ self.resultMessage = "Village not found"
+
+ return villagedetailsdata
+
+ except Exception as e:
+ self.isSuccess = False
+ self.resultMessage = str(e)
+ return None
+
+ def GetAllBlocks(self):
blocks = []
self.isSuccess = False
self.resultMessage = ""
- connection = config.get_db_connection()
+ connection = config.get_db_connection()
if not connection:
return []
- cursor = connection.cursor()
-
try:
- cursor.callproc('GetAllBlocks')
- for result in cursor.stored_results():
- blocks = result.fetchall()
+ with connection.cursor() as cursor:
+ cursor.callproc('GetAllBlocks')
+
+ for result in cursor.stored_results():
+ blocks.extend(result.fetchall())
+
self.isSuccess = True
+ 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)
- finally:
- cursor.close()
- connection.close()
+ self.resultMessage = HtmlHelper.json_response(
+ ResponseHandler.fetch_failure("block"), 500
+ )
+ return []
- return blocks
\ No newline at end of file
+ finally:
+ connection.close()
\ No newline at end of file
diff --git a/templates/add_village.html b/templates/add_village.html
index dd5e4ce..f14e691 100644
--- a/templates/add_village.html
+++ b/templates/add_village.html
@@ -1,21 +1,25 @@
{% extends 'base.html' %}
{% block content %}
+
Village Management
+
+
-
+
+