Compare commits
2 Commits
pankaj-dev
...
618595dab9
| Author | SHA1 | Date | |
|---|---|---|---|
| 618595dab9 | |||
| 1821f04fe0 |
2
.env
2
.env
@@ -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
9
.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
venv/
|
||||||
|
*.pyc
|
||||||
|
__pycache__/
|
||||||
|
.uploads
|
||||||
|
static/download/
|
||||||
|
downloads/
|
||||||
|
uploads/
|
||||||
|
|
||||||
|
|
||||||
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
1
.idea/.name
generated
Normal file
1
.idea/.name
generated
Normal file
@@ -0,0 +1 @@
|
|||||||
|
main.py
|
||||||
10
.idea/ManagementApplicationt.iml
generated
Normal file
10
.idea/ManagementApplicationt.iml
generated
Normal 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>
|
||||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal 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
7
.idea/misc.xml
generated
Normal 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
8
.idea/modules.xml
generated
Normal 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
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
426
activity.log
426
activity.log
@@ -7713,277 +7713,155 @@ Timestamp: 2026-03-21 18:31:17 | User: Unknown | Action: Search Contractor | Det
|
|||||||
Timestamp: 2026-03-21 18:31:17 | User: Unknown | Action: Search Contractor | Details:
|
Timestamp: 2026-03-21 18:31:17 | User: Unknown | Action: Search Contractor | Details:
|
||||||
Timestamp: 2026-03-21 18:31: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:
|
|
||||||
|
|||||||
@@ -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():
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
|
||||||
@@ -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'))
|
||||||
@@ -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
|
||||||
)
|
)
|
||||||
@@ -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
|
||||||
|
|||||||
498
model/Invoice.py
498
model/Invoice.py
@@ -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)
|
||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
|
||||||
231
model/Report.py
231
model/Report.py
@@ -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
0
model/ReportGenerator.py
Normal file
266
model/State.py
266
model/State.py
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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 ]+$"
|
||||||
|
|||||||
174
model/Village.py
174
model/Village.py
@@ -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()
|
||||||
@@ -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 %}
|
||||||
Reference in New Issue
Block a user