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 + + - +
    +