2 Commits

Author SHA1 Message Date
618595dab9 Remove downloads and uploads folders from tracking 2026-03-23 12:35:03 +05:30
1821f04fe0 Recovered lost local code 2026-03-23 12:31:04 +05:30
28 changed files with 1668 additions and 1842 deletions

2
.env
View File

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

9
.gitignore vendored Normal file
View File

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

3
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

1
.idea/.name generated Normal file
View File

@@ -0,0 +1 @@
main.py

10
.idea/ManagementApplicationt.iml generated Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.13" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

7
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.13 (ManagementApplicationt)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/ManagementApplicationt.iml" filepath="$PROJECT_DIR$/.idea/ManagementApplicationt.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@@ -0,0 +1 @@
# MA07-05-2025

View File

@@ -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: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-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 13:44:03 | User: Unknown | Action: Login | Details:
Timestamp: 2026-03-22 12:27:17 | User: Unknown | Action: Edit Subcontractor | Details: Timestamp: 2026-03-22 13:51:01 | User: Unknown | Action: Check Block | Details:
Timestamp: 2026-03-22 12:27:31 | User: Unknown | Action: Add Subcontractor | Details: Timestamp: 2026-03-22 13:51:01 | User: Unknown | Action: Check Block | Details:
Timestamp: 2026-03-22 12:27:39 | User: Unknown | Action: Edit Subcontractor | Details: Timestamp: 2026-03-22 13:51:01 | User: Unknown | Action: Check Block | Details:
Timestamp: 2026-03-22 12:32:18 | User: Unknown | Action: Edit Subcontractor | Details: Timestamp: 2026-03-22 13:51:01 | User: Unknown | Action: Check Block | Details:
Timestamp: 2026-03-22 12:33:19 | User: Unknown | Action: Add Subcontractor | Details: Timestamp: 2026-03-22 13:51:03 | User: Unknown | Action: Check Block | Details:
Timestamp: 2026-03-22 12:33:40 | User: Unknown | Action: Edit Subcontractor | Details: Timestamp: 2026-03-22 13:51:04 | User: Unknown | Action: Add Block | Details:
Timestamp: 2026-03-22 12:40:57 | User: Unknown | Action: Check State | Details: Timestamp: 2026-03-22 13:51:45 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 12:40:58 | User: Unknown | Action: Add State | Details: Timestamp: 2026-03-22 13:51:46 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 12:42:22 | User: Unknown | Action: Check State | Details: Timestamp: 2026-03-22 13:51:46 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 12:42:23 | User: Unknown | Action: Add State | Details: Timestamp: 2026-03-22 13:51:46 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 12:42:28 | User: Unknown | Action: Edit State | Details: Timestamp: 2026-03-22 13:51:46 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 12:42:37 | User: Unknown | Action: Edit State | Details: Timestamp: 2026-03-22 13:51:47 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 12:42:42 | User: Unknown | Action: Delete State | Details: Timestamp: 2026-03-22 13:51:47 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 12:45:49 | User: Unknown | Action: Add Payment | Details: Timestamp: 2026-03-22 13:51:49 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 12:46:08 | User: Unknown | Action: Edit Payment | Details: Timestamp: 2026-03-22 13:51:49 | User: Unknown | Action: Add Village | Details:
Timestamp: 2026-03-22 12:46:14 | User: Unknown | Action: Delete Payment | Details: Timestamp: 2026-03-22 14:02:44 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 13:00:54 | User: Unknown | Action: Get hold type | Details: Timestamp: 2026-03-22 14:02:44 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 13:16:59 | User: Unknown | Action: Check State | Details: Timestamp: 2026-03-22 14:02:45 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 13:17:00 | User: Unknown | Action: Add State | Details: Timestamp: 2026-03-22 14:02:45 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 13:17:08 | User: Unknown | Action: Edit State | Details: Timestamp: 2026-03-22 14:02:45 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 13:17:12 | User: Unknown | Action: Delete State | Details: Timestamp: 2026-03-22 14:02:46 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 13:17:16 | User: Unknown | Action: Check State | Details: Timestamp: 2026-03-22 14:02:46 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 13:17:16 | User: Unknown | Action: Check State | Details: Timestamp: 2026-03-22 14:02:46 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 13:17:17 | User: Unknown | Action: Check State | Details: Timestamp: 2026-03-22 14:02:46 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 13:17:17 | User: Unknown | Action: Check State | Details: Timestamp: 2026-03-22 14:02:46 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 13:17:17 | User: Unknown | Action: Check State | Details: Timestamp: 2026-03-22 14:02:46 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 13:17:17 | User: Unknown | Action: Check State | Details: Timestamp: 2026-03-22 14:02:47 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 13:17:34 | User: Unknown | Action: Add Subcontractor | Details: Timestamp: 2026-03-22 14:02:47 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 13:17:43 | User: Unknown | Action: Edit Subcontractor | Details: Timestamp: 2026-03-22 14:02:49 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 13:18:07 | User: Unknown | Action: Edit Subcontractor | Details: Timestamp: 2026-03-22 14:02:49 | User: Unknown | Action: Add Village | Details:
Timestamp: 2026-03-22 14:41:43 | User: Unknown | Action: Login | Details: Timestamp: 2026-03-22 14:41:45 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 14:41:52 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 14:41:45 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 14:41:53 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 14:41:45 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 14:43:32 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 14:41:46 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 14:43:32 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 14:41:46 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 14:43:33 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 14:41:46 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 14:43:33 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 14:41:47 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 14:43:33 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 14:41:48 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 14:43:33 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 14:41:48 | User: Unknown | Action: Add Village | Details:
Timestamp: 2026-03-22 14:43:34 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 14:42:03 | User: Unknown | Action: Delete Village | Details:
Timestamp: 2026-03-22 14:43:34 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 14:46:40 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:34 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 14:46:46 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:34 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:13:08 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:34 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:14:05 | User: Unknown | Action: Add invoice | Details:
Timestamp: 2026-03-22 14:43:34 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:14:10 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:35 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:22:44 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:35 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:24:26 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:35 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:24:26 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:35 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:24:27 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:35 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:24:27 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:36 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:24:27 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:36 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:24:27 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:37 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:24:27 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:37 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:24:28 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:38 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:24:28 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:38 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:24:28 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:38 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:24:28 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:39 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:24:28 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:39 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:24:28 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:39 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:24:29 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:40 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:24:52 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:40 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:36:04 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:40 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:36:05 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:40 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:44:04 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:41 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:44:05 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:41 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:44:16 | User: Unknown | Action: Delete Invoice | Details:
Timestamp: 2026-03-22 14:43:41 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:44:29 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:41 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:46:02 | User: Unknown | Action: Edit invoice | Details:
Timestamp: 2026-03-22 14:43:41 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:46:13 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:42 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:46:39 | User: Unknown | Action: Edit invoice | Details:
Timestamp: 2026-03-22 14:43:42 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:46:46 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:42 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:46:58 | User: Unknown | Action: Delete Invoice | Details:
Timestamp: 2026-03-22 14:43:42 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:48:39 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:43 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:55:40 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:43 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:57:59 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:43 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:58:19 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:43 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:58:19 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:43 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:58:20 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:44 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:58:20 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:44 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 16:58:20 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:44 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 17:01:33 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:44 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 17:01:34 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:45 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 17:01:34 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:45 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 17:01:34 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:45 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 17:01:34 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:45 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 17:04:33 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:45 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 17:07:03 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:46 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 17:09:23 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:46 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 17:10:08 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:55 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 17:12:47 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:55 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 17:12:48 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:57 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 17:12:48 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:43:57 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 17:12:49 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:44:18 | User: Unknown | Action: Upload Excel File | Details: Timestamp: 2026-03-22 17:15:32 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:44:26 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:15:32 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:44:26 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:15:32 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:44:26 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:15:32 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:44:27 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:15:33 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:44:27 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:19:27 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:44:27 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:19:27 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:44:27 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:19:27 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:44:41 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:19:27 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:44:51 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:19:32 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:46:12 | User: Unknown | Action: Upload Excel File | Details: Timestamp: 2026-03-22 17:19:32 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:46:18 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:19:39 | User: Unknown | Action: Delete Invoice | Details:
Timestamp: 2026-03-22 14:46:18 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:31:10 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:46:18 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:31:26 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:46:18 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:31:36 | User: Unknown | Action: Delete Invoice | Details:
Timestamp: 2026-03-22 14:46:18 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:31:42 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:46:18 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:32:24 | User: Unknown | Action: Edit invoice | Details:
Timestamp: 2026-03-22 14:46:18 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:32:31 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:46:18 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:33:48 | User: Unknown | Action: Add invoice | Details:
Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:33:50 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:34:01 | User: Unknown | Action: Delete Invoice | Details:
Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:34:24 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:34:41 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:49:57 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:50:06 | User: Unknown | Action: Delete Invoice | Details:
Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:54:09 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 17:57:09 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 18:24:21 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 18:24:29 | User: Unknown | Action: Delete Invoice | Details:
Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 18:24:33 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 18:25:34 | User: Unknown | Action: Edit invoice | Details:
Timestamp: 2026-03-22 14:46:19 | User: Unknown | Action: Data saved | Details: Timestamp: 2026-03-22 18:25:43 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:46:29 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 18:38:34 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:46:29 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 18:38:40 | User: Unknown | Action: Delete invoice | Details:
Timestamp: 2026-03-22 14:46:31 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 18:39:42 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:46:31 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 18:41:47 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-03-22 14:46:31 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 18:42:08 | User: Unknown | Action: Delete Village | Details:
Timestamp: 2026-03-22 14:46:31 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 18:42:16 | User: Unknown | Action: Delete Village | Details:
Timestamp: 2026-03-22 14:46:34 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 18:43:44 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 14:46:34 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 18:43:44 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 14:46:35 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 18:43:44 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 14:46:35 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 18:43:45 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 14:46:35 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 18:43:45 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 14:46:35 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 18:43:46 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 14:46:35 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 18:43:46 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 14:46:35 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 18:43:47 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 14:46:37 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 18:43:50 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-03-22 14:46:38 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 18:43:51 | User: Unknown | Action: Add Village | Details:
Timestamp: 2026-03-22 14:46:39 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 18:47:22 | User: Unknown | Action: Edit Village | Details:
Timestamp: 2026-03-22 14:46:39 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 18:51:57 | User: Unknown | Action: Edit Village | Details:
Timestamp: 2026-03-22 14:46:39 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 18:53:38 | User: Unknown | Action: Edit Village | Details:
Timestamp: 2026-03-22 14:46:40 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 18:57:49 | User: Unknown | Action: Edit Village | Details:
Timestamp: 2026-03-22 14:46:40 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 19:00:14 | User: Unknown | Action: Edit Village | Details:
Timestamp: 2026-03-22 14:46:40 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 19:03:21 | User: Unknown | Action: Edit Village | Details:
Timestamp: 2026-03-22 14:46:40 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 19:06:23 | User: Unknown | Action: Edit Village | Details:
Timestamp: 2026-03-22 14:46:40 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 19:10:30 | User: Unknown | Action: Edit Village | Details:
Timestamp: 2026-03-22 14:46:41 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-22 19:10:41 | User: Unknown | Action: Delete Village | Details:
Timestamp: 2026-03-22 14:46:43 | User: Unknown | Action: Search Contractor | Details: Timestamp: 2026-03-23 11:55:40 | User: Unknown | Action: Add GST Release | 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:

View File

@@ -6,21 +6,20 @@ import openpyxl
from flask import Blueprint, request, render_template, redirect, url_for, jsonify, current_app from flask import Blueprint, request, render_template, redirect, url_for, jsonify, current_app
from flask_login import current_user from flask_login import current_user
from model.Log import LogHelper from model.Log import LogHelper
import config import config # your database connection module
from model.FolderAndFile import FolderAndFile
excel_bp = Blueprint('excel', __name__) excel_bp = Blueprint('excel', __name__)
# Default folder in case config not set # Default folder in case config not set
# DEFAULT_UPLOAD_FOLDER = 'uploads' DEFAULT_UPLOAD_FOLDER = 'uploads'
# def get_upload_folder(): def get_upload_folder():
# """Returns the upload folder from Flask config or default, ensures it exists.""" """Returns the upload folder from Flask config or default, ensures it exists."""
# folder = current_app.config.get('UPLOAD_FOLDER', DEFAULT_UPLOAD_FOLDER) folder = current_app.config.get('UPLOAD_FOLDER', DEFAULT_UPLOAD_FOLDER)
# if not os.path.exists(folder): if not os.path.exists(folder):
# os.makedirs(folder) os.makedirs(folder)
# return folder return folder
# ---------------- Upload Excel File ---------------- # ---------------- Upload Excel File ----------------
@@ -30,11 +29,8 @@ def upload():
if request.method == 'POST': if request.method == 'POST':
file = request.files.get('file') file = request.files.get('file')
if file and file.filename.endswith('.xlsx'): if file and file.filename.endswith('.xlsx'):
# upload_folder = get_upload_folder() upload_folder = get_upload_folder()
# filepath = os.path.join(upload_folder, file.filename) filepath = os.path.join(upload_folder, file.filename)
filepath =FolderAndFile.get_upload_path(file.filename)
file.save(filepath) file.save(filepath)
LogHelper.log_action( LogHelper.log_action(
@@ -51,8 +47,7 @@ def show_table(filename):
global data global data
data = [] data = []
# filepath = os.path.join(get_upload_folder(), filename) filepath = os.path.join(get_upload_folder(), filename)
filepath = FolderAndFile.get_upload_path(filename)
wb = openpyxl.load_workbook(filepath, data_only=True) wb = openpyxl.load_workbook(filepath, data_only=True)
sheet = wb.active sheet = wb.active
@@ -74,6 +69,7 @@ def show_table(filename):
try: try:
cursor = connection.cursor(dictionary=True) cursor = connection.cursor(dictionary=True)
print(f"Calling GetStateByName with: {file_info['State']}")
cursor.callproc('GetStateByName', [file_info['State']]) cursor.callproc('GetStateByName', [file_info['State']])
for result in cursor.stored_results(): for result in cursor.stored_results():
state_data = result.fetchone() 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.") errors.append(f"State '{file_info['State']}' is not valid. Please add it.")
if state_data: 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']]) cursor.callproc('GetDistrictByNameAndStates', [file_info['District'], state_data['State_ID']])
for result in cursor.stored_results(): for result in cursor.stored_results():
district_data = result.fetchone() 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']}'.") errors.append(f"District '{file_info['District']}' is not valid under state '{file_info['State']}'.")
if district_data: 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']]) cursor.callproc('GetBlockByNameAndDistricts', [file_info['Block'], district_data['District_ID']])
for result in cursor.stored_results(): for result in cursor.stored_results():
block_data = result.fetchone() block_data = result.fetchone()
if not block_data: if not block_data:
errors.append(f"Block '{file_info['Block']}' is not valid under district '{file_info['District']}'.") 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']]) cursor.callproc('GetSubcontractorByName', [file_info['Subcontractor']])
for result in cursor.stored_results(): for result in cursor.stored_results():
subcontractor_data = result.fetchone() subcontractor_data = result.fetchone()
if not subcontractor_data: if not subcontractor_data:
print(f"Inserting subcontractor: {file_info['Subcontractor']}")
cursor.callproc('InsertSubcontractor', [file_info['Subcontractor']]) cursor.callproc('InsertSubcontractor', [file_info['Subcontractor']])
connection.commit() connection.commit()
cursor.callproc('GetSubcontractorByName', [file_info['Subcontractor']]) cursor.callproc('GetSubcontractorByName', [file_info['Subcontractor']])
for result in cursor.stored_results(): for result in cursor.stored_results():
subcontractor_data = result.fetchone() subcontractor_data = result.fetchone()
print("Calling GetAllHoldTypes")
cursor.callproc("GetAllHoldTypes") cursor.callproc("GetAllHoldTypes")
hold_types_data = [] hold_types_data = []
for ht in cursor.stored_results(): for ht in cursor.stored_results():

View File

@@ -1,3 +1,105 @@
# # 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 "<li>No subcontractor found</li>"
# output = "".join(
# f"<li data-id='{row['Contractor_Id']}'>{row['Contractor_Name']}</li>"
# 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/<int:invoice_id>', 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/<int:invoice_id>', 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 # controllers/invoice_controller.py
from flask import Blueprint, request, jsonify, render_template from flask import Blueprint, request, jsonify, render_template
@@ -7,92 +109,92 @@ from model.Log import LogHelper
invoice_bp = Blueprint('invoice', __name__) invoice_bp = Blueprint('invoice', __name__)
# -------------------------------- Add Invoice --------------------------------- # ------------------------------- Helpers -------------------------------
def handle_exception(func):
"""Decorator to handle exceptions and return JSON error responses."""
def wrapper(*args, **kwargs):
try:
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']) @invoice_bp.route('/add_invoice', methods=['GET', 'POST'])
@login_required @login_required
@handle_exception
def add_invoice(): def add_invoice():
if request.method == 'POST': if request.method == 'POST':
try: data = request.form
village_name = request.form.get('village') village_name = data.get('village')
village_result = get_village_id(village_name) village_result = get_village_id(village_name)
if not village_result: if not village_result:
return jsonify({"status": "error", "message": f"Village '{village_name}' not found"}), 400 return jsonify({"status": "error", "message": f"Village '{village_name}' not found"}), 400
village_id = village_result['Village_Id'] village_id = village_result['Village_Id']
data = request.form
invoice_id = insert_invoice(data, village_id) invoice_id = insert_invoice(data, village_id)
assign_subcontractor(data, village_id) assign_subcontractor(data, village_id)
insert_hold_types(data, invoice_id) insert_hold_types(data, invoice_id)
LogHelper.log_action("Add invoice", f"User {current_user.id} Added invoice '{data.get('pmc_no')}'") log_action("Add invoice", f"added invoice '{data.get('pmc_no')}'")
return jsonify({"status": "success", "message": "Invoice added successfully"}), 201 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() invoices = get_all_invoice_details()
villages = get_all_villages() villages = get_all_villages()
return render_template('add_invoice.html', invoices=invoices, villages=villages) return render_template('add_invoice.html', invoices=invoices, villages=villages)
# ------------------- Search Subcontractor ------------------- # ------------------------------- Search Subcontractor -------------------------------
@invoice_bp.route('/search_subcontractor', methods=['POST']) @invoice_bp.route('/search_subcontractor', methods=['POST'])
@login_required @login_required
@handle_exception
def search_subcontractor(): def search_subcontractor():
sub_query = request.form.get("query") query = request.form.get("query", "").strip()
results = search_contractors(sub_query) results = search_contractors(query)
if not results: if not results:
return "<li>No subcontractor found</li>" return "<li>No subcontractor found</li>"
output = "".join( return "".join(f"<li data-id='{r['Contractor_Id']}'>{r['Contractor_Name']}</li>" for r in results)
f"<li data-id='{row['Contractor_Id']}'>{row['Contractor_Name']}</li>"
for row in results
)
return output
# ------------------- Get Hold Types ------------------- # ------------------------------- Get Hold Types -------------------------------
@invoice_bp.route('/get_hold_types', methods=['GET']) @invoice_bp.route('/get_hold_types', methods=['GET'])
@login_required @login_required
@handle_exception
def get_hold_types(): def get_hold_types():
hold_types = get_all_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) return jsonify(hold_types)
# ------------------- Edit Invoice ------------------- # ------------------------------- Edit Invoice -------------------------------
@invoice_bp.route('/edit_invoice/<int:invoice_id>', methods=['GET', 'POST']) @invoice_bp.route('/edit_invoice/<int:invoice_id>', methods=['GET', 'POST'])
@login_required @login_required
@handle_exception
def edit_invoice(invoice_id): def edit_invoice(invoice_id):
if request.method == 'POST': if request.method == 'POST':
data = request.form data = request.form
update_invoice(data, invoice_id) update_invoice(data, invoice_id)
update_inpayment(data) update_inpayment(data)
log_action("Edit invoice", f"edited invoice '{invoice_id}'")
LogHelper.log_action("Edit invoice", f"User {current_user.id} Edit invoice '{invoice_id}'")
return jsonify({"status": "success", "message": "Invoice updated successfully"}), 200 return jsonify({"status": "success", "message": "Invoice updated successfully"}), 200
invoice = get_invoice_by_id(invoice_id) invoice = get_invoice_by_id(invoice_id)
return render_template('edit_invoice.html', invoice=invoice) return render_template('edit_invoice.html', invoice=invoice)
# ------------------- Delete Invoice ------------------- # ------------------------------- Delete Invoice -------------------------------
@invoice_bp.route('/delete_invoice/<int:invoice_id>', methods=['GET']) @invoice_bp.route('/delete_invoice/<int:invoice_id>', methods=['GET'])
@login_required @login_required
@handle_exception
def delete_invoice_route(invoice_id): def delete_invoice_route(invoice_id):
try:
delete_invoice_data(invoice_id, current_user.id) delete_invoice_data(invoice_id, current_user.id)
LogHelper.log_action("Delete Invoice", f"User {current_user.id} deleted Invoice '{invoice_id}'") log_action("Delete invoice", f"deleted invoice '{invoice_id}'")
return jsonify({ return jsonify({"status": "success", "message": f"Invoice {invoice_id} deleted successfully."})
"message": f"Invoice {invoice_id} deleted successfully.",
"status": "success"
})
except Exception as e:
return jsonify({
"message": str(e),
"status": "error"
}), 500

View File

@@ -1,13 +1,13 @@
from flask import Blueprint, render_template, send_from_directory from flask import Blueprint, render_template, send_from_directory
from flask_login import login_required, current_user
from model.PmcReport import PmcReport from model.PmcReport import PmcReport
pmc_report_bp = Blueprint("pmc_report", __name__) pmc_report_bp = Blueprint("pmc_report", __name__)
@pmc_report_bp.route("/pmc_report/<pmc_no>") @pmc_report_bp.route("/pmc_report/<pmc_no>")
@login_required
def pmc_report(pmc_no): def pmc_report(pmc_no):
data = PmcReport.get_pmc_report(pmc_no) data = PmcReport.get_pmc_report(pmc_no)
if not data: if not data:
return "No PMC found with this number", 404 return "No PMC found with this number", 404
@@ -24,7 +24,6 @@ def pmc_report(pmc_no):
) )
@pmc_report_bp.route("/download_pmc_report/<pmc_no>") @pmc_report_bp.route("/download_pmc_report/<pmc_no>")
@login_required
def download_pmc_report(pmc_no): def download_pmc_report(pmc_no):
result = PmcReport.download_pmc_report(pmc_no) result = PmcReport.download_pmc_report(pmc_no)

View File

@@ -3,11 +3,11 @@ from flask_login import login_required, current_user
from model.Report import ReportHelper from model.Report import ReportHelper
from model.Log import LogHelper from model.Log import LogHelper
import config import config
from datetime import datetime
import os import os
import openpyxl import openpyxl
from openpyxl.styles import Font from openpyxl.styles import Font
from model.ContractorInfo import ContractorInfo from model.ContractorInfo import ContractorInfo
from model.FolderAndFile import FolderAndFile
report_bp = Blueprint("report", __name__) report_bp = Blueprint("report", __name__)
@@ -26,17 +26,35 @@ def report_page():
def search_contractor(): def search_contractor():
subcontractor_name = request.form.get("subcontractor_name") 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( LogHelper.log_action(
"Search Contractor", "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) return jsonify(data)
# ---------------- Contractor Report ---------------- # ---------------- Contractor Report ----------------
@report_bp.route('/contractor_report/<int:contractor_id>') @report_bp.route('/contractor_report/<int:contractor_id>')
@login_required @login_required
def contractor_report(contractor_id): def contractor_report(contractor_id):
@@ -49,145 +67,136 @@ def contractor_report(contractor_id):
**data **data
) )
class FilePathData:
downloadReportFolder = "static/download"
@report_bp.route('/download_report/<int:contractor_id>') @report_bp.route('/download_report/<int:contractor_id>')
@login_required @login_required
def download_report(contractor_id): def download_report(contractor_id):
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
# -------- Invoice Data --------
cursor.callproc('FetchInvoicesByContractor', [contractor_id])
invoices = []
for result in cursor.stored_results():
invoices.extend(result.fetchall())
# @report_bp.route('/download_report/<int:contractor_id>') if not invoices:
# @login_required return "No invoice data found"
# def download_report(contractor_id):
# try:
# connection = config.get_db_connection()
# cursor = connection.cursor(dictionary=True)
# # -------- Contractor Info -------- # -------- Create Workbook --------
# contractor = ContractorInfo(contractor_id) workbook = openpyxl.Workbook()
# contInfo = contractor.contInfo sheet = workbook.active
sheet.title = "Contractor Report"
# if not contInfo: # ================= CONTRACTOR DETAILS =================
# return "No contractor found", 404 sheet.append(["SUB CONTRACTOR DETAILS"])
sheet.cell(row=sheet.max_row, column=1).font = Font(bold=True)
sheet.append([])
# # -------- Invoice Data -------- sheet.append(["Name", contInfo.get("Contractor_Name") or ""])
# cursor.callproc('FetchInvoicesByContractor', [contractor_id]) 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([])
# invoices = [] # ================= TABLE HEADERS =================
# for result in cursor.stored_results(): headers = [
# invoices.extend(result.fetchall()) "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)
# if not invoices: # ================= DATA =================
# return "No invoice data found" total_final = 0
total_payment = 0
total_amount = 0
# # -------- Create Workbook -------- for inv in invoices:
# workbook = openpyxl.Workbook() row = [
# sheet = workbook.active inv.get("PMC_No"),
# sheet.title = "Contractor Report" 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")
]
# # ================= CONTRACTOR DETAILS ================= total_final += float(inv.get("Final_Amount") or 0)
# sheet.append(["SUB CONTRACTOR DETAILS"]) total_payment += float(inv.get("Payment_Amount") or 0)
# sheet.cell(row=sheet.max_row, column=1).font = Font(bold=True) total_amount += float(inv.get("Total_Amount") or 0)
# sheet.append([])
# sheet.append(["Name", contInfo.get("Contractor_Name") or ""]) sheet.append(row)
# 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 ================= # ================= TOTAL ROW =================
# headers = [ sheet.append([])
# "PMC No", "Village", "Invoice No", "Invoice Date", "Work Type","Invoice_Details", sheet.append([
# "Basic Amount", "Debit Amount", "After Debit Amount", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
# "Amount", "GST Amount", "TDS Amount", "SD Amount", "TOTAL",
# "On Commission", "Hydro Testing", "Hold Amount", total_final,
# "GST SD Amount", "Final Amount", total_payment,
# "Payment Amount", "TDS Payment", "",
# "Total Amount", "UTR" total_amount,
# ] ""
# sheet.append(headers) ])
# for col in range(1, len(headers) + 1):
# sheet.cell(row=sheet.max_row, column=col).font = Font(bold=True)
# # ================= DATA ================= # ================= AUTO WIDTH =================
# total_final = 0 for column in sheet.columns:
# total_payment = 0 max_length = 0
# total_amount = 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
# for inv in invoices: # ================= SAVE FILE =================
# row = [ output_folder = "downloads"
# inv.get("PMC_No"), os.makedirs(output_folder, exist_ok=True)
# inv.get("Village_Name"), filename = f"Contractor_Report_{contInfo.get('Contractor_Name')}.xlsx"
# inv.get("invoice_no"), output_file = os.path.join(output_folder, filename)
# inv.get("Invoice_Date"), workbook.save(output_file)
# 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) return send_file(output_file, as_attachment=True)
# total_payment += float(inv.get("Payment_Amount") or 0)
# total_amount += float(inv.get("Total_Amount") or 0)
# sheet.append(row) except Exception as e:
return str(e)
# # ================= TOTAL ROW =================
# sheet.append([])
# sheet.append([
# "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
# "TOTAL",
# total_final,
# total_payment,
# "",
# total_amount,
# ""
# ])
# # ================= AUTO WIDTH =================
# for column in sheet.columns:
# max_length = 0
# column_letter = column[0].column_letter
# for cell in column:
# if cell.value:
# max_length = max(max_length, len(str(cell.value)))
# sheet.column_dimensions[column_letter].width = max_length + 2
# # ================= SAVE FILE =================
# # output_folder = "downloads"
# # os.makedirs(output_folder, exist_ok=True)
# # filename = f"Contractor_Report_{contInfo.get('Contractor_Name')}.xlsx"
# # output_file = os.path.join(output_folder, filename)
# filename = f"Contractor_Report_{contInfo.get('Contractor_Name')}.xlsx"
# output_file = FolderAndFile.get_download_path(filename)
# workbook.save(output_file)
# return send_file(output_file, as_attachment=True)
# except Exception as e:
# return str(e)

View File

@@ -1,12 +1,12 @@
# controllers/subcontractor_controller.py
from flask import Blueprint, render_template, request, redirect, url_for, jsonify from flask import Blueprint, render_template, request, redirect, url_for, jsonify
from flask_login import login_required from flask_login import login_required
from model.Subcontractor import Subcontractor from model.Subcontractor import Subcontractor
from model.Log import LogHelper
subcontractor_bp = Blueprint('subcontractor', __name__) subcontractor_bp = Blueprint('subcontractor', __name__)
# ---------------------------------------------------------- # Simple replacements for missing HtmlHelper and ResponseHandler
# Helpers (unchanged)
# ----------------------------------------------------------
class HtmlHelper: class HtmlHelper:
@staticmethod @staticmethod
def json_response(data, status=200): def json_response(data, status=200):
@@ -30,88 +30,71 @@ class ResponseHandler:
return {"status": "error", "message": f"Failed to delete {entity}"} return {"status": "error", "message": f"Failed to delete {entity}"}
# ----------------------------------------------------------
# LIST + ADD
# ----------------------------------------------------------
@subcontractor_bp.route('/subcontractor', methods=['GET', 'POST']) @subcontractor_bp.route('/subcontractor', methods=['GET', 'POST'])
@login_required @login_required
def subcontract(): def subcontract():
subcontractor = []
sub = Subcontractor()
# ---------------- GET ----------------
if request.method == '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': if request.method == 'POST':
contractor_data = {
sub.AddSubcontractor(request) 'Contractor_Name': request.form['Contractor_Name'],
'Address': request.form['Address'],
if not sub.isSuccess: 'Mobile_No': request.form['Mobile_No'],
return HtmlHelper.json_response( 'PAN_No': request.form['PAN_No'],
ResponseHandler.add_failure("Subcontractor"), 500 'Email': request.form['Email'],
) 'Gender': request.form['Gender'],
'GST_Registration_Type': request.form['GST_Registration_Type'],
# Reload list after insert 'GST_No': request.form['GST_No'],
subcontractor = sub.GetAllSubcontractors(request) '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()
return render_template('add_subcontractor.html', subcontractor=subcontractor) return render_template('add_subcontractor.html', subcontractor=subcontractor)
# ----------------------------------------------------------
# EDIT
# ----------------------------------------------------------
@subcontractor_bp.route('/edit_subcontractor/<int:id>', methods=['GET', 'POST']) @subcontractor_bp.route('/edit_subcontractor/<int:id>', methods=['GET', 'POST'])
@login_required @login_required
def edit_subcontractor(id): def edit_subcontractor(id):
subcontractor, error = Subcontractor.get_subcontractor_by_id(id)
sub = Subcontractor() if error:
return HtmlHelper.json_response(ResponseHandler.fetch_failure("Subcontractor"), 500)
# Fetch data
subcontractor = sub.GetSubcontractorByID(id)
if not subcontractor: if not subcontractor:
return HtmlHelper.json_response( return HtmlHelper.json_response(ResponseHandler.fetch_failure("Subcontractor"), 404)
ResponseHandler.fetch_failure("Subcontractor"), 404
)
# ---------------- POST (UPDATE) ----------------
if request.method == 'POST': if request.method == 'POST':
updated_data = {
sub.EditSubcontractor(request, id) 'Contractor_Name': request.form['Contractor_Name'],
'Address': request.form['Address'],
if not sub.isSuccess: 'Mobile_No': request.form['Mobile_No'],
return HtmlHelper.json_response( 'PAN_No': request.form['PAN_No'],
ResponseHandler.update_failure("Subcontractor"), 500 '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 redirect(url_for('subcontractor.subcontract'))
return render_template('edit_subcontractor.html', subcontractor=subcontractor) return render_template('edit_subcontractor.html', subcontractor=subcontractor)
# ----------------------------------------------------------
# DELETE
# ----------------------------------------------------------
@subcontractor_bp.route('/deleteSubContractor/<int:id>', methods=['GET', 'POST']) @subcontractor_bp.route('/deleteSubContractor/<int:id>', methods=['GET', 'POST'])
@login_required @login_required
def deleteSubContractor(id): def deleteSubContractor(id):
error, affected_rows = Subcontractor.delete_subcontractor(id)
sub = Subcontractor() if error:
return HtmlHelper.json_response(ResponseHandler.delete_failure("Subcontractor"), 500)
sub.DeleteSubcontractor(request, id) if affected_rows == 0:
return HtmlHelper.json_response(ResponseHandler.fetch_failure("Subcontractor not deleted"), 404)
if not sub.isSuccess:
return HtmlHelper.json_response(
ResponseHandler.delete_failure("Subcontractor"), 500
)
return redirect(url_for('subcontractor.subcontract')) return redirect(url_for('subcontractor.subcontract'))

View File

@@ -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/<int:state_id>')
# @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/<int:district_id>')
# @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/<int:village_id>')
# @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/<int:village_id>', 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 import Blueprint, render_template, request, redirect, url_for, flash, jsonify
from flask_login import login_required from flask_login import login_required
import config import config
from model.Village import Village from model.Village import Village
from model.State import State from model.State import State
@@ -23,7 +192,6 @@ def add_village():
state = State() state = State()
states = state.GetAllStates(request=request) states = state.GetAllStates(request=request)
villages = village.GetAllVillages(request=request) villages = village.GetAllVillages(request=request)
return render_template( return render_template(
@@ -42,7 +210,6 @@ def get_districts(state_id):
cursor = connection.cursor() cursor = connection.cursor()
cursor.callproc("GetDistrictByStateID", [state_id]) cursor.callproc("GetDistrictByStateID", [state_id])
districts = [] districts = []
for rs in cursor.stored_results(): for rs in cursor.stored_results():
@@ -51,15 +218,7 @@ def get_districts(state_id):
cursor.close() cursor.close()
connection.close() connection.close()
district_list = [] return jsonify([{"id": d[0], "name": d[1]} for d in districts])
for d in districts:
district_list.append({
"id": d[0],
"name": d[1]
})
return jsonify(district_list)
# ------------------------- Fetch Blocks ------------------------- # ------------------------- Fetch Blocks -------------------------
@@ -71,7 +230,6 @@ def get_blocks(district_id):
cursor = connection.cursor() cursor = connection.cursor()
cursor.callproc("GetBlocksByDistrictID", [district_id]) cursor.callproc("GetBlocksByDistrictID", [district_id])
blocks = [] blocks = []
for rs in cursor.stored_results(): for rs in cursor.stored_results():
@@ -80,22 +238,13 @@ def get_blocks(district_id):
cursor.close() cursor.close()
connection.close() connection.close()
block_list = [] return jsonify([{"id": b[0], "name": b[1]} for b in blocks])
for b in blocks:
block_list.append({
"id": b[0],
"name": b[1]
})
return jsonify(block_list)
# ------------------------- Check Village ------------------------- # ------------------------- Check Village -------------------------
@village_bp.route('/check_village', methods=['POST']) @village_bp.route('/check_village', methods=['POST'])
@login_required @login_required
def check_village(): def check_village():
village = Village() village = Village()
return village.CheckVillage(request=request) return village.CheckVillage(request=request)
@@ -106,14 +255,9 @@ def check_village():
def delete_village(village_id): def delete_village(village_id):
village = Village() village = Village()
village.DeleteVillage(request=request, village_id=village_id) village.DeleteVillage(request=request, village_id=village_id)
if not village.isSuccess: flash(village.resultMessage, "success" if village.isSuccess else "error")
flash(village.resultMessage, "error")
else:
flash(village.resultMessage, "success")
return redirect(url_for('village.add_village')) return redirect(url_for('village.add_village'))
@@ -135,8 +279,8 @@ def edit_village(village_id):
else: else:
flash(village.resultMessage, "error") flash(village.resultMessage, "error")
village_data = village.GetVillageByID(request=request, id=village_id) village_data = village.GetVillageByID(id=village_id) or []
blocks = village.GetAllBlocks(request=request) blocks = village.GetAllBlocks() or []
return render_template( return render_template(
'edit_village.html', 'edit_village.html',
@@ -145,23 +289,17 @@ def edit_village(village_id):
) )
else: else:
# ✅ FIXED HERE (removed request)
village_data = village.GetVillageByID(request=request, id=village_id) village_data = village.GetVillageByID(id=village_id)
if not village.isSuccess: if not village.isSuccess:
flash(village.resultMessage, "error") flash(village.resultMessage, "error")
return redirect(url_for('village.add_village')) return redirect(url_for('village.add_village'))
blocks = village.GetAllBlocks(request=request) blocks = village.GetAllBlocks() or []
if village_data is None:
village_data = []
if blocks is None:
blocks = []
return render_template( return render_template(
'edit_village.html', 'edit_village.html',
village_data=village_data, village_data=village_data or [],
blocks=blocks blocks=blocks
) )

View File

@@ -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 from mysql.connector import Error
import config import config
import openpyxl
import os
import re
import ast
from datetime import datetime from datetime import datetime
class ContractorInfo: class ContractorInfo:
ID = "" def __init__(self, contractor_id):
contInfo = None self.ID = contractor_id
def __init__(self, id): self.contInfo = None
self.ID = id
print(id)
self.fetchData() self.fetchData()
def fetchData(self): def fetchData(self):
"""Fetch basic contractor info by ID."""
try: try:
connection = config.get_db_connection() connection = config.get_db_connection()
cursor = connection.cursor(dictionary=True, buffered=True) with connection.cursor(dictionary=True, buffered=True) as cursor:
cursor.callproc('GetContractorInfoById', [self.ID]) cursor.callproc('GetContractorInfoById', [self.ID])
# Get the first result set
for result in cursor.stored_results(): for result in cursor.stored_results():
self.contInfo = result.fetchone() self.contInfo = result.fetchone()
except Error as e:
print(self.contInfo,flush=True) print(f"Error fetching contractor info: {e}")
finally: finally:
cursor.close() if connection.is_connected():
connection.close() connection.close()
def fetchalldata(self): def fetchalldata(self):
"""Fetch hold types and invoices for contractor."""
data = {}
try: try:
connection = config.get_db_connection() connection = config.get_db_connection()
cursor = connection.cursor(dictionary=True, buffered=True) with connection.cursor(dictionary=True, buffered=True) as cursor:
print("here", flush=True) # Fetch Hold Types
# ---------------- Hold Types ----------------
cursor = connection.cursor(dictionary=True)
cursor.callproc('GetHoldTypesByContractor', [self.ID]) cursor.callproc('GetHoldTypesByContractor', [self.ID])
hold_types = [] hold_types = []
for result in cursor.stored_results(): for result in cursor.stored_results():
hold_types = result.fetchall() hold_types = result.fetchall()
hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types} hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types}
data['hold_types'] = hold_type_map
# ---------------- Invoices ---------------- # Fetch Invoices
cursor = connection.cursor(dictionary=True)
cursor.callproc('GetInvoicesByContractor', [self.ID]) cursor.callproc('GetInvoicesByContractor', [self.ID])
invoices = [] invoices = []
for result in cursor.stored_results(): for result in cursor.stored_results():
invoices = result.fetchall() invoices = result.fetchall()
# Remove duplicate invoices # Remove duplicate invoices
invoice_ids_seen = set() seen_ids = set()
unique_invoices = [] unique_invoices = []
for inv in invoices: for inv in invoices:
if inv["Invoice_Id"] not in invoice_ids_seen: if inv['Invoice_Id'] not in seen_ids:
invoice_ids_seen.add(inv["Invoice_Id"]) seen_ids.add(inv['Invoice_Id'])
unique_invoices.append(inv) unique_invoices.append(inv)
invoices = unique_invoices data['invoices'] = unique_invoices
except Error as e:
print(f"Error fetching contractor data: {e}")
finally: finally:
cursor.close() if connection.is_connected():
connection.close() connection.close()
return data

View File

@@ -1,274 +1,29 @@
import config import config
import mysql.connector import mysql.connector
# ------------------- Helper ------------------- # ------------------- Helper Functions -------------------
def clear_results(cursor): def clear_results(cursor):
"""Consume all stored results to prevent cursor issues."""
for r in cursor.stored_results(): for r in cursor.stored_results():
r.fetchall() r.fetchall()
def fetch_one(cursor):
# ------------------- Get Village Id ------------------- """Fetch first row from stored results."""
def get_village_id(village_name):
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
cursor.callproc('InsertInvoice', [
data.get('pmc_no'),
village_id,
data.get('work_type'),
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)
])
invoice_id = None
for result in cursor.stored_results(): for result in cursor.stored_results():
row = result.fetchone() return result.fetchone()
if row: return None
invoice_id = row.get('invoice_id')
if not invoice_id:
raise Exception("Invoice ID not returned")
# 2. Insert Inpayment
cursor.callproc('InsertInpayment', [
data.get('pmc_no'),
village_id,
data.get('work_type'),
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),
data.get('subcontractor_id')
])
clear_results(cursor)
connection.commit()
return invoice_id
except Exception as e:
connection.rollback()
raise e
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
def fetch_all(cursor):
"""Fetch all rows from stored results."""
data = []
for result in cursor.stored_results(): for result in cursor.stored_results():
hold_type_result = result.fetchone() data.extend(result.fetchall())
return data
if not hold_type_result: def get_numeric_values(data):
cursor.callproc('InsertHoldType', [hold_type, 0]) """Return numeric fields for invoices safely."""
cursor.execute("SELECT @_InsertHoldType_1") return [
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)
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)
cursor.callproc('GetInvoiceDetailsById', [invoice_id])
invoice = None
for result in cursor.stored_results():
invoice = result.fetchone()
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:
cursor.callproc("GetVillageIdByName", (data.get('village'),))
village = None
for rs in cursor.stored_results():
village = rs.fetchone()
village_id = village['Village_Id']
numeric = [
float(data.get('basic_amount') or 0), float(data.get('basic_amount') or 0),
float(data.get('debit_amount') or 0), float(data.get('debit_amount') or 0),
float(data.get('after_debit_amount') or 0), float(data.get('after_debit_amount') or 0),
@@ -282,6 +37,97 @@ def update_invoice(data, invoice_id):
float(data.get('final_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)
try:
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,
data.get('work_type'),
data.get('invoice_details'),
data.get('invoice_date'),
data.get('invoice_no'),
*get_numeric_values(data)
])
invoice_row = fetch_one(cursor)
if not invoice_row:
raise Exception("Invoice ID not returned")
invoice_id = invoice_row.get('invoice_id')
# Insert inpayment
cursor.callproc('InsertInpayment', [
data.get('pmc_no'),
village_id,
data.get('work_type'),
data.get('invoice_details'),
data.get('invoice_date'),
data.get('invoice_no'),
*get_numeric_values(data),
data.get('subcontractor_id')
])
clear_results(cursor)
return invoice_id
return execute_db_operation(operation)
def get_all_invoice_details():
def operation(cursor):
cursor.callproc('GetAllInvoiceDetails')
return fetch_all(cursor)
return execute_db_operation(operation)
def get_invoice_by_id(invoice_id):
def operation(cursor):
cursor.callproc('GetInvoiceDetailsById', [invoice_id])
invoice = fetch_one(cursor)
cursor.callproc('GetHoldAmountsByInvoiceId', [invoice_id])
hold_amounts = fetch_all(cursor)
if invoice:
invoice["hold_amounts"] = hold_amounts
return invoice
return execute_db_operation(operation)
def update_invoice(data, invoice_id):
def operation(cursor):
cursor.callproc("GetVillageIdByName", (data.get('village'),))
village = fetch_one(cursor)
if not village:
raise Exception("Village not found")
village_id = village['Village_Id']
cursor.callproc('UpdateInvoice', [ cursor.callproc('UpdateInvoice', [
data.get('pmc_no'), data.get('pmc_no'),
village_id, village_id,
@@ -289,91 +135,101 @@ def update_invoice(data, invoice_id):
data.get('invoice_details'), data.get('invoice_details'),
data.get('invoice_date'), data.get('invoice_date'),
data.get('invoice_no'), data.get('invoice_no'),
*numeric, *get_numeric_values(data),
invoice_id invoice_id
]) ])
clear_results(cursor) 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): def update_inpayment(data):
connection = config.get_db_connection() def operation(cursor):
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),
]
cursor.callproc('UpdateInpayment', [ cursor.callproc('UpdateInpayment', [
data.get('work_type'), data.get('work_type'),
data.get('invoice_details'), data.get('invoice_details'),
data.get('invoice_date'), data.get('invoice_date'),
*numeric, *get_numeric_values(data),
data.get('pmc_no'), data.get('pmc_no'),
data.get('invoice_no') data.get('invoice_no')
]) ])
clear_results(cursor) 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): def delete_invoice_data(invoice_id, user_id):
connection = config.get_db_connection() def operation(cursor):
cursor = connection.cursor(dictionary=True) # Fetch PMC and Invoice_No from DB
cursor.callproc('GetInvoicePMCById', (invoice_id,))
try:
cursor.callproc('GetInvoicePMCById', [invoice_id])
record = {} record = {}
for result in cursor.stored_results(): for result in cursor.stored_results():
record = result.fetchone() or {} record = result.fetchone() or {}
if not record: if not record:
raise Exception("Invoice not found") 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,)) cursor.callproc("DeleteInvoice", (invoice_id,))
clear_results(cursor) clear_results(cursor)
cursor.callproc( # Delete inpayment
'DeleteInpaymentByPMCInvoice', cursor.callproc('DeleteInpaymentByPMCInvoice', (pmc_no, invoice_no))
[record['PMC_No'], record['invoice_no']] clear_results(cursor)
)
connection.commit() execute_db_operation(operation)
except Exception as e:
connection.rollback()
raise e
finally: # ------------------- Subcontractor Functions -------------------
cursor.close() def assign_subcontractor(data, village_id):
connection.close() 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)

View File

@@ -21,8 +21,6 @@ class itemCRUDMapping:
self.name = "State" self.name = "State"
elif itemType is ItemCRUDType.HoldType: elif itemType is ItemCRUDType.HoldType:
self.name = "Hold Type" self.name = "Hold Type"
elif itemType is ItemCRUDType.Subcontractor:
self.name = "Subcontractor"
else: else:
self.name = "Item" self.name = "Item"
@@ -56,16 +54,12 @@ class ItemCRUD:
connection.commit() connection.commit()
self.isSuccess = True self.isSuccess = True
self.resultMessage = HtmlHelper.json_response( self.resultMessage = ResponseHandler.delete_success(self.itemCRUDMapping.name)['message']
ResponseHandler.delete_success(self.itemCRUDMapping.name), 200
)
except mysql.connector.Error as e: except mysql.connector.Error as e:
print(f"Error deleting {self.itemCRUDMapping.name}: {e}") print(f"Error deleting {self.itemCRUDMapping.name}: {e}")
self.isSuccess = False self.isSuccess = False
self.resultMessage = HtmlHelper.json_response( self.resultMessage = ResponseHandler.delete_failure(self.itemCRUDMapping.name)['message']
ResponseHandler.delete_failure(self.itemCRUDMapping.name), 500
)
finally: finally:
cursor.close() cursor.close()
@@ -74,7 +68,7 @@ class ItemCRUD:
# ---------------------------------------------------------- # ----------------------------------------------------------
# ADD # 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() connection = config.get_db_connection()
if not connection: if not connection:
@@ -88,53 +82,10 @@ class ItemCRUD:
LogHelper.log_action( LogHelper.log_action(
f"Add {self.itemCRUDMapping.name}", 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}'"
) )
try: # Validation
# ======================================================
# 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): if not re.match(RegEx.patternAlphabetOnly, childname):
self.isSuccess = False self.isSuccess = False
self.resultMessage = HtmlHelper.json_response( self.resultMessage = HtmlHelper.json_response(
@@ -142,16 +93,20 @@ class ItemCRUD:
) )
return return
# Duplicate check try:
# Call check procedure
if parentid is None: if parentid is None:
cursor.callproc(storedprocfetch, (childname,)) cursor.callproc(storedprocfetch, (childname,))
else: else:
cursor.callproc(storedprocfetch, (childname, parentid)) cursor.callproc(storedprocfetch, (childname, parentid))
# ✅ FIX: initialize variable
existing_item = None existing_item = None
for rs in cursor.stored_results(): for rs in cursor.stored_results():
existing_item = rs.fetchone() existing_item = rs.fetchone()
# Check duplicate
if existing_item: if existing_item:
self.isSuccess = False self.isSuccess = False
self.resultMessage = HtmlHelper.json_response( self.resultMessage = HtmlHelper.json_response(
@@ -169,7 +124,6 @@ class ItemCRUD:
self.isSuccess = True self.isSuccess = True
self.resultMessage = HtmlHelper.json_response( self.resultMessage = HtmlHelper.json_response(
ResponseHandler.add_success(self.itemCRUDMapping.name), 200 ResponseHandler.add_success(self.itemCRUDMapping.name), 200
) )
@@ -187,7 +141,7 @@ class ItemCRUD:
# ---------------------------------------------------------- # ----------------------------------------------------------
# EDIT # 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() connection = config.get_db_connection()
cursor = connection.cursor() cursor = connection.cursor()
@@ -197,40 +151,12 @@ class ItemCRUD:
f"User {current_user.id} edited '{childid}'" f"User {current_user.id} edited '{childid}'"
) )
try:
# ======================================================
# SUBCONTRACTOR (MULTI-FIELD)
# ======================================================
if data:
cursor.callproc(storedprocupdate, (
childid,
data['Contractor_Name'],
data['Address'],
data['Mobile_No'],
data['PAN_No'],
data['Email'],
data['Gender'],
data['GST_Registration_Type'],
data['GST_No'],
data['Contractor_password']
))
connection.commit()
self.isSuccess = True
self.resultMessage = HtmlHelper.json_response(
ResponseHandler.update_success(self.itemCRUDMapping.name), 200
)
return
# ======================================================
# NORMAL
# ======================================================
if not re.match(RegEx.patternAlphabetOnly, childname): if not re.match(RegEx.patternAlphabetOnly, childname):
self.isSuccess = False self.isSuccess = False
self.resultMessage = ResponseHandler.update_failure(self.itemCRUDMapping.name)['message'] self.resultMessage = ResponseHandler.update_failure(self.itemCRUDMapping.name)['message']
return return
try:
if parentid is None: if parentid is None:
cursor.callproc(storedprocupdate, (childid, childname)) cursor.callproc(storedprocupdate, (childid, childname))
else: else:
@@ -335,7 +261,9 @@ class ItemCRUD:
else: else:
cursor.callproc(storedprocfetch, (childname, parentid)) cursor.callproc(storedprocfetch, (childname, parentid))
# ✅ FIX
existing_item = None existing_item = None
for rs in cursor.stored_results(): for rs in cursor.stored_results():
existing_item = rs.fetchone() existing_item = rs.fetchone()

View File

@@ -1,12 +1,11 @@
import os
import openpyxl import openpyxl
from openpyxl.styles import Font, PatternFill from openpyxl.styles import Font, PatternFill
from decimal import Decimal
from datetime import datetime
import config import config
from flask_login import current_user from flask_login import current_user
from model.Log import LogHelper from model.Log import LogHelper
from model.Report import ReportHelper
from model.FolderAndFile import FolderAndFile
class PmcReport: class PmcReport:
@staticmethod @staticmethod
@@ -17,9 +16,8 @@ class PmcReport:
try: try:
# cursor.callproc("GetContractorInfoByPmcNo", (pmc_no,)) cursor.callproc("GetContractorInfoByPmcNo", (pmc_no,))
# pmc_info = next(cursor.stored_results()).fetchone() pmc_info = next(cursor.stored_results()).fetchone()
pmc_info = ReportHelper.execute_sp(cursor, 'GetContractorInfoByPmcNo', [pmc_no], True)
if not pmc_info: if not pmc_info:
return None return None
@@ -33,12 +31,15 @@ class PmcReport:
invoices = [] invoices = []
hold_amount_total = 0 hold_amount_total = 0
if hold_type_ids: if hold_type_ids:
hold_type_ids_str = ",".join(map(str, hold_type_ids)) hold_type_ids_str = ",".join(map(str, hold_type_ids))
cursor.callproc( cursor.callproc(
'GetInvoices_WithHold', 'GetInvoices_WithHold',
[pmc_no, pmc_info["Contractor_Id"], hold_type_ids_str] [pmc_no, pmc_info["Contractor_Id"], hold_type_ids_str]
) )
else: else:
cursor.callproc( cursor.callproc(
'GetInvoices_NoHold', 'GetInvoices_NoHold',
[pmc_no, pmc_info["Contractor_Id"]] [pmc_no, pmc_info["Contractor_Id"]]
@@ -53,42 +54,33 @@ class PmcReport:
# GST RELEASE # GST RELEASE
# cursor.callproc('GetGSTReleaseByPMC', [pmc_no]) cursor.callproc('GetGSTReleaseByPMC', [pmc_no])
# gst_rel = [] gst_rel = []
# for result in cursor.stored_results(): for result in cursor.stored_results():
# gst_rel = result.fetchall() gst_rel = result.fetchall()
gst_rel = ReportHelper.execute_sp(cursor, 'GetGSTReleaseByPMC', [pmc_no])
total_gst_basic = sum(row.get('basic_amount', 0) or 0 for row in gst_rel) 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) total_gst_final = sum(row.get('final_amount', 0) or 0 for row in gst_rel)
# ---------------- HOLD RELEASE ---------------- # ---------------- HOLD RELEASE ----------------
# cursor.callproc('GetHoldReleaseByPMC', [pmc_no]) cursor.callproc('GetHoldReleaseByPMC', [pmc_no])
# hold_release = [] hold_release = []
# for result in cursor.stored_results(): for result in cursor.stored_results():
# hold_release = result.fetchall() hold_release = result.fetchall()
hold_release = ReportHelper.execute_sp(cursor, 'GetHoldReleaseByPMC', [pmc_no])
# ---------------- CREDIT NOTE ---------------- # ---------------- CREDIT NOTE ----------------
# cursor.callproc('GetCreditNoteByPMC', [pmc_no]) cursor.callproc('GetCreditNoteByPMC', [pmc_no])
# credit_note = [] credit_note = []
# for result in cursor.stored_results(): for result in cursor.stored_results():
# credit_note = result.fetchall() credit_note = result.fetchall()
credit_note = ReportHelper.execute_sp(cursor, 'GetCreditNoteByPMC', [pmc_no])
payments = ReportHelper.execute_sp(cursor, 'GetPaymentsByPMC', [pmc_no])
# ---------------- PAYMENTS ---------------- # ---------------- PAYMENTS ----------------
# cursor.callproc('GetPaymentsByPMC', [pmc_no]) cursor.callproc('GetPaymentsByPMC', [pmc_no])
# payments = [] payments = []
# for result in cursor.stored_results(): for result in cursor.stored_results():
# payments = result.fetchall() payments = result.fetchall()
total_pay_amount = sum(row.get('Payment_Amount', 0) or 0 for row in payments) total_pay_amount = sum(row.get('Payment_Amount', 0) or 0 for row in payments)
total_pay_total = sum(row.get('Total_amount', 0) or 0 for row in payments) total_pay_total = sum(row.get('Total_amount', 0) or 0 for row in payments)
@@ -133,73 +125,109 @@ class PmcReport:
def download_pmc_report(pmc_no): def download_pmc_report(pmc_no):
connection = config.get_db_connection() connection = config.get_db_connection()
if not connection: output_folder = "static/download"
return None 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) cursor = connection.cursor(dictionary=True)
try: try:
# filename
filename = f"PMC_Report_{pmc_no}.xlsx"
output_folder = FolderAndFile.get_download_folder() cursor.callproc('GetContractorDetailsByPMC', [pmc_no])
output_file = FolderAndFile.get_download_path(filename) contractor_info = next(cursor.stored_results()).fetchone()
# ================= DATA FETCH =================
contractor_info = ReportHelper.execute_sp(cursor, 'GetContractorDetailsByPMC', [pmc_no], "one")
if not contractor_info: if not contractor_info:
return None 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} 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]) cursor.callproc('GetHoldAmountsByContractor', [contractor_info["Contractor_Id"]])
hold_amounts = next(cursor.stored_results()).fetchall()
# ================= DATA MAPPING =================
hold_data = {} hold_data = {}
for h in hold_amounts: for h in hold_amounts:
hold_data.setdefault(h['Invoice_Id'], {})[h['hold_type_id']] = h['hold_amount'] 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 = {} payments_map = {}
extra_payments = []
for pay in all_payments: for pay in all_payments:
if pay['invoice_no']: if pay['invoice_no']:
payments_map.setdefault(pay['invoice_no'], []).append(pay) 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( LogHelper.log_action(
"Download PMC Report", "Download PMC Report",
f"User {current_user.id} Download PMC Report '{pmc_no}'" f"User {current_user.id} Download PMC Report '{pmc_no}'"
) )
# ================= EXCEL =================
workbook = openpyxl.Workbook() workbook = openpyxl.Workbook()
sheet = workbook.active sheet = workbook.active
sheet.title = "PMC Report" sheet.title = "PMC Report"
# HEADER INFO
sheet.append(["", "", "Laxmi Civil Engineering Services PVT. LTD."]) sheet.append(["", "", "Laxmi Civil Engineering Services PVT. LTD."])
sheet.append(["Contractor Name", contractor_info["Contractor_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"]]) sheet.append(["State", contractor_info["State_Name"], "", "PAN No", contractor_info["PAN_No"], "", "Address", contractor_info["Address"]])
sheet.append(["District", contractor_info["District_Name"]]) sheet.append(["District", contractor_info["District_Name"], "", "Mobile No", contractor_info["Mobile_No"]])
sheet.append(["Block", contractor_info["Block_Name"]]) sheet.append(["Block", contractor_info["Block_Name"], "", "Email", contractor_info["Email"]])
sheet.append([]) sheet.append([])
base_headers = [ base_headers = [
"PMC No","Village","Work Type","Invoice Details","Invoice Date","Invoice No", "PMC No","Village","Work Type","Invoice Details","Invoice Date","Invoice No",
"Basic Amount","Debit","After Debit Amount","GST","Amount","TDS", "Basic Amount","Debit","After Debit Amount","GST (18%)","Amount","TDS (1%)",
"SD","On Commission","Hydro Testing","GST SD Amount" "SD (5%)","On Commission","Hydro Testing","GST SD Amount"
] ]
hold_headers = [ht['hold_type'] for ht in hold_types] hold_headers = [ht['hold_type'] for ht in hold_types]
@@ -208,53 +236,42 @@ class PmcReport:
"Final Amount","Payment Amount","TDS Payment","Total Paid","UTR" "Final Amount","Payment Amount","TDS Payment","Total Paid","UTR"
] ]
headers = base_headers + hold_headers + payment_headers sheet.append(base_headers + hold_headers + payment_headers)
sheet.append(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]: for cell in sheet[sheet.max_row]:
cell.font = Font(bold=True) cell.font = header_font
cell.fill = header_fill
# DATA
seen_invoices = set() seen_invoices = set()
processed_payments = set()
for inv in invoices: for inv in invoices:
invoice_no = inv["Invoice_No"] invoice_no = inv["Invoice_No"]
payments = payments_map.get(invoice_no, []) payments = payments_map.get(invoice_no, [])
if invoice_no in seen_invoices: if invoice_no not in seen_invoices:
continue
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 = [ row = [
pmc_no, pmc_no, inv["Village_Name"], inv["Work_Type"],
inv["Village_Name"], inv["Invoice_Details"], inv["Invoice_Date"], invoice_no,
inv["Work_Type"], inv["Basic_Amount"], inv["Debit_Amount"],
inv["Invoice_Details"], inv["After_Debit_Amount"], inv["GST_Amount"],
inv["Invoice_Date"], inv["Amount"], inv["TDS_Amount"], inv["SD_Amount"],
invoice_no, inv["On_Commission"], inv["Hydro_Testing"], inv["GST_SD_Amount"]
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"]
] ]
# HOLD DATA
invoice_holds = hold_data.get(inv["Invoice_Id"], {}) invoice_holds = hold_data.get(inv["Invoice_Id"], {})
for ht_id in hold_type_map.keys(): for ht_id in hold_type_map.keys():
row.append(invoice_holds.get(ht_id, "")) row.append(invoice_holds.get(ht_id, ""))
# PAYMENT DATA
row += [ row += [
inv["Final_Amount"], inv["Final_Amount"],
first_payment["Payment_Amount"] if first_payment else "", first_payment["Payment_Amount"] if first_payment else "",
@@ -265,192 +282,12 @@ class PmcReport:
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.save(output_file)
workbook.close() workbook.close()
return output_folder, filename return output_folder, f"PMC_Report_{pmc_no}.xlsx"
except Exception as e:
print(f"Error generating PMC report: {e}")
return None
finally: finally:
cursor.close() cursor.close()
connection.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()

View File

@@ -1,68 +1,15 @@
import config import config
from datetime import datetime from datetime import datetime
from flask import send_file
import openpyxl
from openpyxl.styles import Font
from model.FolderAndFile import FolderAndFile
class ReportHelper: class ReportHelper:
isSuccess = False
resultMessage = ""
data=[]
def __init__(self):
self.isSuccess = False
self.resultMessage = ""
self.data = []
@staticmethod @staticmethod
def execute_sp(cursor, proc_name, params=[], fetch_one=False): def search_contractor(subcontractor_name, pmc_no, state, district, block, village, year_from, year_to):
cursor.callproc(proc_name, params)
return (
ReportHelper.fetch_one_result(cursor)
if fetch_one else
ReportHelper.fetch_all_results(cursor)
)
@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() connection = config.get_db_connection()
if not connection:
return []
cursor = connection.cursor(dictionary=True) cursor = connection.cursor(dictionary=True)
try: cursor.callproc("search_contractor_info", [
data = ReportHelper.execute_sp(
cursor,
"search_contractor_info",
[
subcontractor_name or None, subcontractor_name or None,
pmc_no or None, pmc_no or None,
state or None, state or None,
@@ -71,14 +18,12 @@ class ReportHelper:
village or None, village or None,
year_from or None, year_from or None,
year_to or None year_to or None
] ])
)
except Exception as e:
print(f"Error in search_contractor: {e}")
data = [] data = []
for result in cursor.stored_results():
data = result.fetchall()
finally:
cursor.close() cursor.close()
connection.close() connection.close()
@@ -87,24 +32,47 @@ class ReportHelper:
@staticmethod @staticmethod
def get_contractor_report(contractor_id): def get_contractor_report(contractor_id):
connection = config.get_db_connection() connection = config.get_db_connection()
cursor = connection.cursor(dictionary=True, buffered=True) cursor = connection.cursor(dictionary=True, buffered=True)
try: try:
# Contractor Info (only one fetch) # Contractor Info
contInfo = ReportHelper.execute_sp(cursor, 'GetContractorInfo', [contractor_id], True) cursor.callproc('GetContractorInfo', [contractor_id])
for result in cursor.stored_results():
contInfo = result.fetchone()
# Hold Types # 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
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 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
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
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
payments = ReportHelper.execute_sp(cursor, 'GetPayments', [contractor_id]) cursor.callproc('GetPayments', [contractor_id])
for result in cursor.stored_results():
payments = result.fetchall()
# Totals # Totals
total = { total = {
@@ -146,130 +114,3 @@ class ReportHelper:
"total": total, "total": total,
"current_date": current_date "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)

0
model/ReportGenerator.py Normal file
View File

View File

@@ -1,50 +1,79 @@
from flask import request, redirect, url_for from flask import Flask, render_template, request, redirect, url_for, send_from_directory, flash, jsonify, json
from flask_login import current_user 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.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType
from model.Log import LogHelper from model.Log import LogData, LogHelper
from model.ItemCRUD import ItemCRUD
import os
import config import config
import re import re
import mysql.connector
import mysql.connector
from mysql.connector import Error
class State: class State:
isSuccess = False
resultMessage = ""
def __init__(self): def __init__(self):
self.isSuccess = False self.isSuccess = False
self.resultMessage = "" self.resultMessage = ""
# ----------------------------------------------------------
# ADD STATE (USING ITEM CRUD)
# ----------------------------------------------------------
def AddState(self, request): def AddState(self, request):
"""Log user actions with timestamp, user, action, and details."""
state_name = request.form['state_Name'].strip() statedata = []
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):
connection = config.get_db_connection() 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: if not connection:
return [] return []
@@ -54,115 +83,164 @@ class State:
try: try:
cursor.callproc("GetAllStates") cursor.callproc("GetAllStates")
for res in cursor.stored_results(): for res in cursor.stored_results():
data = res.fetchall() statedata = res.fetchall()
self.isSuccess = True self.isSuccess = True
except mysql.connector.Error as e: except mysql.connector.Error as e:
print(f"Error fetching states: {e}") print(f"Error fetching states: {e}")
self.isSuccess = False self.isSuccess = False
self.resultMessage = HtmlHelper.json_response( self.resultMessage = HtmlHelper.json_response(ResponseHandler.fetch_failure("state"), 500)
ResponseHandler.fetch_failure("state"), 500
)
return [] return []
finally: finally:
cursor.close() cursor.close()
connection.close() connection.close()
return data return statedata
# ----------------------------------------------------------
# CHECK STATE (USING ITEM CRUD)
# ----------------------------------------------------------
def CheckState(self, request): def CheckState(self, request):
self.isSuccess = False
self.resultMessage = ""
connection = config.get_db_connection()
#connection closing needs to be verified
if connection:
cursor = connection.cursor()
state_name = request.json.get('state_Name', '').strip() 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)
crud = ItemCRUD(ItemCRUDType.State) 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()
return crud.CheckItem(
request=request,
parentid=None,
childname=state_name,
storedprocfetch="CheckStateExists"
)
# ----------------------------------------------------------
# DELETE STATE (USING ITEM CRUD)
# ----------------------------------------------------------
def DeleteState(self, request, id): def DeleteState(self, request, id):
self.isSuccess = False
self.resultMessage = ""
crud = ItemCRUD(ItemCRUDType.State) 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()
crud.DeleteItem( self.resultMessage = "Successfully Deleted"
request=request, self.isSuccess = True
itemID=id, except mysql.connector.Error as e:
storedprocDelete="DeleteState" print(f"Error deleting data: {e}")
) self.isSuccess = False
self.resultMessage = HtmlHelper.json_response(ResponseHandler.delete_failure("state"), 500)
self.isSuccess = crud.isSuccess return HtmlHelper.json_response(ResponseHandler.delete_failure("state"), 500)
self.resultMessage = crud.resultMessage
finally:
cursor.close()
connection.close()
return self.resultMessage return self.resultMessage
# ----------------------------------------------------------
# EDIT STATE (USING ITEM CRUD)
# ----------------------------------------------------------
def EditState(self, request, id): def EditState(self, request, id):
self.isSuccess = False
state_name = request.form['state_Name'].strip() self.resultMessage = ""
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):
connection = config.get_db_connection() connection = config.get_db_connection()
data = None 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: if not connection:
return None return []
cursor = connection.cursor() cursor = connection.cursor()
try: try:
cursor.callproc("GetStateByID", (id,)) cursor.callproc("GetStateByID", (id,))
for res in cursor.stored_results(): for res in cursor.stored_results():
data = res.fetchone() statedata = res.fetchone()
if data: if statedata:
self.isSuccess = True self.isSuccess = True
self.resultMessage = "Success" self.resultMessage = "Success in Fetching"
else: else:
self.isSuccess = False self.isSuccess = False
self.resultMessage = "Not Found" self.resultMessage = "State Not Found"
except mysql.connector.Error as e: except mysql.connector.Error as e:
print(f"Error fetching state: {e}") print(f"Error fetching states: {e}")
self.isSuccess = False self.isSuccess = False
self.resultMessage = HtmlHelper.json_response(ResponseHandler.fetch_failure("state"), 500)
return []
finally: finally:
cursor.close() cursor.close()
connection.close() connection.close()
return data return statedata

View File

@@ -1,140 +1,131 @@
from model.Utilities import ItemCRUDType # model/Subcontractor.py
from model.ItemCRUD import ItemCRUD
import config
from model.Log import LogHelper
from mysql.connector import Error
class Subcontractor: class Subcontractor:
def __init__(self):
self.isSuccess = False
self.resultMessage = ""
# ---------------------------------------------------------- @staticmethod
# ADD def get_connection():
# ---------------------------------------------------------- return config.get_db_connection()
def AddSubcontractor(self, request):
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 = { @staticmethod
"Contractor_Name": request.form.get('Contractor_Name', '').strip(), def get_subcontractor_by_id(id):
"Address": request.form.get('Address', '').strip(), connection = Subcontractor.get_connection()
"Mobile_No": request.form.get('Mobile_No', '').strip(), subcontractor = None
"PAN_No": request.form.get('PAN_No', '').strip(), if not connection:
"Email": request.form.get('Email', '').strip(), return None, "Database connection failed"
"Gender": request.form.get('Gender', '').strip(), try:
"GST_Registration_Type": request.form.get('GST_Registration_Type', '').strip(), cursor = connection.cursor()
"GST_No": request.form.get('GST_No', '').strip(), cursor.callproc("GetSubcontractorById", (id,))
"Contractor_password": request.form.get('Contractor_password', '').strip() 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( @staticmethod
request=request, def save_subcontractor(data):
data=data, connection = Subcontractor.get_connection()
storedprocfetch="GetSubcontractorByName", if not connection:
storedprocadd="SaveContractor" 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 @staticmethod
self.resultMessage = subcontractor.resultMessage def update_subcontractor(id, data):
return 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
# ---------------------------------------------------------- @staticmethod
# GET ALL def delete_subcontractor(id):
# ---------------------------------------------------------- connection = Subcontractor.get_connection()
def GetAllSubcontractors(self, request): if not connection:
return "Database connection failed", 0
subcontractor = ItemCRUD(itemType=ItemCRUDType.Subcontractor) affected_rows = 0
try:
data = subcontractor.GetAllData( cursor = connection.cursor()
request=request, cursor.callproc('DeleteSubcontractor', (id,))
storedproc="GetAllSubcontractors" connection.commit()
) for result in cursor.stored_results():
row = result.fetchone()
self.isSuccess = subcontractor.isSuccess affected_rows = row[0] if row else 0
self.resultMessage = subcontractor.resultMessage # Active log
return data LogHelper.log_action("Delete Subcontractor", f"Deleted subcontractor '{id}'")
except Error as e:
# ---------------------------------------------------------- print(f"Error deleting subcontractor: {e}")
# GET BY ID return str(e), 0
# ---------------------------------------------------------- finally:
def GetSubcontractorByID(self, id): cursor.close()
connection.close()
subcontractor = ItemCRUD(itemType=ItemCRUDType.Subcontractor) return None, affected_rows
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

View File

@@ -7,8 +7,6 @@ class ItemCRUDType(Enum):
District = 3 District = 3
State = 4 State = 4
HoldType = 5 HoldType = 5
Subcontractor = 6
class RegEx: class RegEx:
patternAlphabetOnly = "^[A-Za-z ]+$" patternAlphabetOnly = "^[A-Za-z ]+$"

View File

@@ -1,14 +1,7 @@
# return blocks
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user from model.Utilities import ResponseHandler, HtmlHelper, ItemCRUDType
from model.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType
from model.Log import LogData, LogHelper
import config import config
import mysql.connector import mysql.connector
from mysql.connector import Error
from model.ItemCRUD import ItemCRUD from model.ItemCRUD import ItemCRUD
@@ -19,70 +12,123 @@ class Village:
def __init__(self): def __init__(self):
self.isSuccess = False self.isSuccess = False
self.resultMessage = "" 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): 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') if not village_name:
village_name = request.form.get('Village_Name', '').strip() self.isSuccess = False
self.resultMessage = "Village name cannot be empty"
village.AddItem(request=request, parentid=block_id, childname=village_name, storedprocfetch="GetVillageByNameAndBlock", storedprocadd="SaveVillage" )
self.isSuccess = village.isSuccess
self.resultMessage = village.resultMessage
return 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): def GetAllVillages(self, request):
village = ItemCRUD(itemType=ItemCRUDType.Village)
villagesdata = village.GetAllData(request=request, storedproc="GetAllVillages") try:
self.isSuccess = village.isSuccess villagesdata = self.village.GetAllData(
self.resultMessage = village.resultMessage request=request,
storedproc="GetAllVillages"
)
self._set_status(self.village)
return villagesdata return villagesdata
except Exception as e:
self.isSuccess = False
self.resultMessage = str(e)
return []
def CheckVillage(self, request): def CheckVillage(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:
result = village.CheckItem(request=request, parentid=block_id, childname=village_name, storedprocfetch="GetVillageByNameAndBlocks") self.isSuccess = False
self.isSuccess = village.isSuccess self.resultMessage = "Village name cannot be empty"
self.resultMessage = village.resultMessage return None
try:
result = self.village.CheckItem(
request=request,
parentid=block_id,
childname=village_name,
storedprocfetch="GetVillageByNameAndBlocks"
)
self._set_status(self.village)
return result return result
except Exception as e:
self.isSuccess = False
self.resultMessage = str(e)
return None
def DeleteVillage(self, request, village_id): 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" ) except Exception as e:
self.isSuccess = village.isSuccess self.isSuccess = False
self.resultMessage = village.resultMessage self.resultMessage = str(e)
return
def EditVillage(self, request, village_id): def EditVillage(self, request, village_id):
corsor=None block_id, village_name = self._get_form_data(request)
village = ItemCRUD(itemType=ItemCRUDType.Village)
block_id = request.form.get('block_Id') if not village_name:
village_name = request.form.get('Village_Name', '').strip() self.isSuccess = False
self.resultMessage = "Village name cannot be empty"
village.EditItem(request=request,childid=village_id,parentid=block_id,childname=village_name,storedprocupdate="UpdateVillage" )
self.isSuccess = village.isSuccess
self.resultMessage = village.resultMessage
return return
# def GetVillageByID(self, request, id): try:
self.village.EditItem(
request=request,
childid=village_id,
parentid=block_id,
childname=village_name,
storedprocupdate="UpdateVillage"
)
self._set_status(self.village)
# village = ItemCRUD(itemType=ItemCRUDType.Village) except Exception as e:
# villagedetailsdata = village.GetAllData(request=request, storedproc="GetVillageDetailsById") self.isSuccess = False
# self.isSuccess = village.isSuccess self.resultMessage = str(e)
# self.resultMessage = village.resultMessage
# return villagedetailsdata def GetVillageByID(self, id):
try:
villagedetailsdata = self.village.GetDataByID(
id=id,
storedproc="GetVillageDetailsById"
)
def GetVillageByID(self, request, id):
village = ItemCRUD(itemType=ItemCRUDType.Village)
villagedetailsdata = village.GetDataByID(id=id,storedproc="GetVillageDetailsById")
if villagedetailsdata: if villagedetailsdata:
self.isSuccess = True self.isSuccess = True
else: else:
@@ -91,31 +137,37 @@ class Village:
return villagedetailsdata return villagedetailsdata
except Exception as e:
self.isSuccess = False
self.resultMessage = str(e)
return None
def GetAllBlocks(self, request): def GetAllBlocks(self):
blocks = [] blocks = []
self.isSuccess = False self.isSuccess = False
self.resultMessage = "" self.resultMessage = ""
connection = config.get_db_connection()
connection = config.get_db_connection()
if not connection: if not connection:
return [] return []
cursor = connection.cursor()
try: try:
with connection.cursor() as cursor:
cursor.callproc('GetAllBlocks') cursor.callproc('GetAllBlocks')
for result in cursor.stored_results(): for result in cursor.stored_results():
blocks = result.fetchall() blocks.extend(result.fetchall())
self.isSuccess = True self.isSuccess = True
return blocks
except mysql.connector.Error as e: except mysql.connector.Error as e:
print(f"Error fetching blocks: {e}") print(f"Error fetching blocks: {e}")
self.isSuccess = False self.isSuccess = False
self.resultMessage = HtmlHelper.json_response(ResponseHandler.fetch_failure("block"), 500) self.resultMessage = HtmlHelper.json_response(
finally: ResponseHandler.fetch_failure("block"), 500
cursor.close() )
connection.close() return []
return blocks finally:
connection.close()

View File

@@ -1,21 +1,25 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block content %} {% block content %}
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Village Management</title> <title>Village Management</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}"> <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/village.js') }}"></script> <script src="{{ url_for('static', filename='js/village.js') }}"></script>
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script> <script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
</head> </head>
<body> <body>
<!-- Button Container to Center Buttons --> <!-- ===================== BUTTONS ===================== -->
<div class="button-container"> <div class="button-container">
<button id="addButton" class="action-button">Add</button> <button id="addButton" class="action-button">Add</button>
<button id="displayButton" class="action-button">Display</button> <button id="displayButton" class="action-button">Display</button>
</div> </div>
<!-- ===================== ADD FORM ===================== -->
<div id="addForm" style="display: none;"> <div id="addForm" style="display: none;">
<div class="container"> <div class="container">
<div class="form-block"> <div class="form-block">
@@ -49,6 +53,7 @@
</div> </div>
</div> </div>
<!-- ===================== DISPLAY TABLE ===================== -->
<div id="addTable" style="display: none;"> <div id="addTable" style="display: none;">
<div class="search-container"> <div class="search-container">
<h2>Display Villages</h2> <h2>Display Villages</h2>
@@ -63,31 +68,35 @@
<span class="sort-buttons"> <span class="sort-buttons">
<span class="sort-asc">⬆️</span> <span class="sort-asc">⬆️</span>
<span class="sort-desc">⬇️</span> <span class="sort-desc">⬇️</span>
</span></th> </span>
<th class="sortable-header">Block Name </th>
<th class="sortable-header">
Block Name
<span class="sort-buttons"> <span class="sort-buttons">
<span class="sort-asc">⬆️</span> <span class="sort-asc">⬆️</span>
<span class="sort-desc">⬇️</span> <span class="sort-desc">⬇️</span>
</span></th> </span>
</th>
<th>Update</th> <th>Update</th>
<th>Delete</th> <th>Delete</th>
</tr> </tr>
{% for village in villages %} {% for village in villages %}
<tr> <tr>
<td>{{ village[0] }}</td> <td>{{ village[0] }}</td>
<td>{{ village[1] }}</td> <td>{{ village[1] }}</td>
<td>{{ village[2] }}</td> <td>{{ village[2] }}</td>
<td> <td>
<a href="{{ url_for('village.edit_village', village_id=village[0]) }}"> <a href="{{ url_for('village.edit_village', village_id=village[0]) }}">
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit" <img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" class="icon">
class="icon">
</a> </a>
</td> </td>
<td> <td>
<a href="{{ url_for('village.delete_village', village_id=village[0]) }}" <a href="{{ url_for('village.delete_village', village_id=village[0]) }}"
onclick="return confirm('Are you sure you want to delete this village?');"> onclick="return confirm('Are you sure you want to delete this village?');">
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete" <img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" class="icon">
class="icon">
</a> </a>
</td> </td>
</tr> </tr>
@@ -95,5 +104,16 @@
</table> </table>
</div> </div>
<!-- ===================== BROWSER ALERT FLASH ===================== -->
<script>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
alert({{ message|tojson|safe }});
{% endfor %}
{% endif %}
{% endwith %}
</script>
</body> </body>
{% endblock %} {% endblock %}