42 Commits

Author SHA1 Message Date
1cf0093029 Merge pull request 'pankaj-dev' (#20) from pankaj-dev into main
Reviewed-on: #20
2026-04-03 06:43:39 +00:00
73cd97f3c8 optimize and add new service of get report and download report. 2026-04-03 12:10:47 +05:30
0b72adef7d updated code by aakash 2026-03-30 11:36:16 +05:30
225475e843 Merge pull request 'GST Release Add, Edit, Delete Working' (#19) from swapnil-dev into main
Reviewed-on: #19
2026-03-24 13:23:46 +00:00
Swapnil9693
d84ba520cf GST Release Add, Edit, Delete Working 2026-03-24 18:46:07 +05:30
0aeaf775dd Merge pull request 'pankaj-dev - all done' (#18) from pankaj-dev into main
Reviewed-on: #18
2026-03-24 11:27:55 +00:00
88e8771b51 add log file function 2026-03-24 16:56:23 +05:30
6c74b5d3bf Merge branch 'main' of https://gitea.lcepl.org/pjpatil12/Payment_Reconciliation into pankaj-dev 2026-03-24 16:29:32 +05:30
47ba78d72c search on table 2026-03-24 16:29:18 +05:30
1946a98d59 Merge pull request 'Invoice Add Edit and Delete Done' (#17) from swapnil-dev into main
Reviewed-on: #17
2026-03-24 10:51:43 +00:00
8f35e08429 Merge pull request 'GST Release Display Chages' (#16) from laxmi-dev into main
Reviewed-on: #16
Reviewed-by: Pankaj J Patil <pankajjpatil2001@gmail.com>
2026-03-24 10:51:05 +00:00
82bedc3117 Update activity.log 2026-03-24 10:49:06 +00:00
cb68e454bc Update .env 2026-03-24 10:47:05 +00:00
Swapnil9693
91b078a0c3 edit_invoice html removed 2026-03-24 16:16:43 +05:30
Swapnil9693
eb46929893 New invoice commit 2026-03-24 16:13:04 +05:30
675301df7f GST Release Display Chages 2026-03-24 16:08:37 +05:30
Swapnil9693
14e799a1d4 Inoive add update delete messages shown properly 2026-03-24 15:51:55 +05:30
8ab1b69033 Merge pull request 'hold type updated , delete done by prajkta' (#13) from pankaj-dev into main
Reviewed-on: #13
2026-03-24 09:51:42 +00:00
dbeec9962d hold type updated , delete done by prajkta 2026-03-24 15:19:38 +05:30
8750f268db Merge pull request 'Village Add, Edit and Delete Messages done' (#12) from swapnil-dev into main
Reviewed-on: #12
2026-03-24 09:47:16 +00:00
Swapnil9693
b78526ad9f Village Add, Edit and Delete Messages done 2026-03-24 13:41:00 +05:30
7146391c18 Merge pull request 'delete payment code updated by prajakta' (#11) from pankaj-dev into main
Reviewed-on: #11
2026-03-24 07:21:43 +00:00
94b5563d15 delete payment code updated by prajakta 2026-03-24 12:50:44 +05:30
937018dc16 Merge pull request 'add item crude' (#10) from pankaj-dev into main
Reviewed-on: #10
2026-03-24 07:07:31 +00:00
eda238c235 add itemcrude 2026-03-24 12:36:15 +05:30
f184d6cecc Merge pull request 'update block redirect added' (#9) from pankaj-dev into main
Reviewed-on: #9
2026-03-24 06:26:39 +00:00
e7646eee76 Merge pull request 'Village module delete issue resolved and also message shown in alert' (#8) from swapnil-dev into main
Reviewed-on: #8
2026-03-24 06:25:19 +00:00
64ca39944b update block redirect added 2026-03-24 11:47:57 +05:30
Swapnil9693
6b4beb5af8 Village module delete issue resolved and also message shown on alert 2026-03-24 11:43:16 +05:30
Swapnil9693
d092eb0527 Sync .env and activity.log with main 2026-03-24 11:39:08 +05:30
Swapnil9693
f9e9612df5 Re-add .env and activity.log 2026-03-24 11:37:08 +05:30
Swapnil9693
46ec2c0276 Remove sensitive files (.env, activity.log) from repo 2026-03-24 11:32:00 +05:30
Swapnil9693
630ee1744f Backup Before Changes village Task 2026-03-24 11:28:14 +05:30
2679554e98 Merge pull request 'edit comments main code' (#7) from pankaj-dev into main
Reviewed-on: #7
2026-03-24 04:55:48 +00:00
0912aef85e edit comments 2026-03-23 18:45:16 +05:30
ce90c6b350 Merge pull request 'pankaj-dev' (#6) from pankaj-dev into main
Reviewed-on: #6
2026-03-23 11:52:17 +00:00
bc20a53f26 updated code of prajakta block,payment, gst 2026-03-23 17:19:21 +05:30
42f69773ec Merge branch 'main' of https://gitea.lcepl.org/pjpatil12/Payment_Reconciliation into pankaj-dev 2026-03-23 14:31:57 +05:30
79ea359b1c Merge pull request 'pankaj-dev' (#4) from pankaj-dev into main
Reviewed-on: #4
2026-03-23 09:01:20 +00:00
acbea7942c Merge branch 'main' of https://gitea.lcepl.org/pjpatil12/Payment_Reconciliation into pankaj-dev 2026-03-23 14:15:59 +05:30
13a4c5836e remove commented code 2026-03-23 14:15:11 +05:30
af15b3934e Added gitignore 2026-03-23 11:55:16 +05:30
121 changed files with 3631 additions and 11382 deletions

7
.gitignore vendored Normal file
View File

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

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

114
app.log
View File

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

View File

@@ -6,7 +6,6 @@ from model.Log import LogHelper
auth_bp = Blueprint('auth', __name__)
@auth_bp.route('/login', methods=['GET', 'POST'])
def login():

View File

@@ -1,37 +1,28 @@
from flask import Blueprint, render_template, request, redirect, url_for, jsonify
import config
from flask import Blueprint, render_template, request, redirect, url_for, jsonify, flash
from flask_login import login_required
import config
import mysql.connector
from model.State import State
from model.Block import Block
from model.Utilities import HtmlHelper
block_bp = Blueprint('block', __name__)
block = Block()
# --- Add Block page -------
@block_bp.route('/add_block', methods=['GET', 'POST'])
@login_required
def add_block():
block = Block()
# block = Block()
if request.method == 'POST':
block.AddBlock(request)
return block.resultMessage
connection = config.get_db_connection()
cursor = connection.cursor()
cursor.callproc("GetAllStates")
for rs in cursor.stored_results():
states = rs.fetchall()
state = State()
states = state.GetAllStates(request=request)
block_data = block.GetAllBlocks(request)
cursor.close()
connection.close()
return render_template(
'add_block.html',
states=states,
@@ -71,7 +62,7 @@ def get_districts(state_id):
@login_required
def check_block():
block = Block()
# block = Block()
return block.CheckBlock(request)
@@ -79,12 +70,19 @@ def check_block():
@login_required
def edit_block(block_id):
block = Block()
# block = Block()
if request.method == 'POST':
block.EditBlock(request, block_id)
return block.resultMessage
block.resultMessage
if block.resultMessage:
flash("Block updated successfully!", "success")
return redirect(url_for('block.add_block'))
else:
flash(block.resultMessage, "error")
connection = config.get_db_connection()
cursor = connection.cursor()
@@ -92,7 +90,10 @@ def edit_block(block_id):
for rs in cursor.stored_results():
states = rs.fetchall()
cursor.callproc("GetAllDistrictsData")
# cursor.callproc("GetAllDistrictsData")
# for rs in cursor.stored_results():
# districts = rs.fetchall()
cursor.callproc("GetAllDistricts")
for rs in cursor.stored_results():
districts = rs.fetchall()
@@ -113,7 +114,7 @@ def edit_block(block_id):
@login_required
def delete_block(block_id):
block = Block()
# block = Block()
block.DeleteBlock(request, block_id)
return redirect(url_for('block.add_block'))

View File

@@ -5,13 +5,13 @@ from model.District import District
from model.State import State
district_bp = Blueprint('district', __name__)
district = District()
# ------- District page --------
@district_bp.route('/add_district', methods=['GET', 'POST'])
@login_required
def add_district():
district = District()
# district = District()
if request.method == 'POST':
district.AddDistrict(request=request)
@@ -28,21 +28,21 @@ def add_district():
states=states
)
# ------- District check --------
@district_bp.route('/check_district', methods=['POST'])
@login_required
def check_district():
district = District()
# district = District()
return district.CheckDistrict(request=request)
# ------- District delete by district id --------
@district_bp.route('/delete_district/<int:district_id>')
@login_required
def delete_district(district_id):
district = District()
# district = District()
district.DeleteDistrict(request=request, district_id=district_id)
@@ -52,11 +52,12 @@ def delete_district(district_id):
return redirect(url_for('district.add_district'))
# ------- District update by district id --------
@district_bp.route('/edit_district/<int:district_id>', methods=['GET', 'POST'])
@login_required
def edit_district(district_id):
district = District()
# district = District()
state = State()
if request.method == 'POST':

View File

@@ -1,28 +1,16 @@
import os
import config
import ast
import re
from flask_login import login_required
import openpyxl
from flask import Blueprint, request, render_template, redirect, url_for, jsonify, current_app
from flask_login import current_user
from flask_login import login_required
from flask import Blueprint, request, render_template, redirect, url_for, jsonify
from model.Log import LogHelper
import config
from model.FolderAndFile import FolderAndFile
excel_bp = Blueprint('excel', __name__)
# Default folder in case config not set
# DEFAULT_UPLOAD_FOLDER = 'uploads'
# def get_upload_folder():
# """Returns the upload folder from Flask config or default, ensures it exists."""
# folder = current_app.config.get('UPLOAD_FOLDER', DEFAULT_UPLOAD_FOLDER)
# if not os.path.exists(folder):
# os.makedirs(folder)
# return folder
# ---------------- Upload Excel File ----------------
@excel_bp.route('/upload_excel_file', methods=['GET', 'POST'])
@login_required
@@ -30,9 +18,6 @@ def upload():
if request.method == 'POST':
file = request.files.get('file')
if file and file.filename.endswith('.xlsx'):
# upload_folder = get_upload_folder()
# filepath = os.path.join(upload_folder, file.filename)
filepath =FolderAndFile.get_upload_path(file.filename)
file.save(filepath)
@@ -42,6 +27,7 @@ def upload():
f"User {current_user.id} Upload Excel File '{file.filename}'"
)
return redirect(url_for('excel.show_table', filename=file.filename))
return render_template('uploadExcelFile.html')
@@ -51,7 +37,6 @@ def show_table(filename):
global data
data = []
# filepath = os.path.join(get_upload_folder(), filename)
filepath = FolderAndFile.get_upload_path(filename)
wb = openpyxl.load_workbook(filepath, data_only=True)
sheet = wb.active
@@ -74,21 +59,21 @@ def show_table(filename):
try:
cursor = connection.cursor(dictionary=True)
cursor.callproc('GetStateByName', [file_info['State']])
cursor.callproc('CheckStateExists', [file_info['State']])
for result in cursor.stored_results():
state_data = result.fetchone()
if not state_data:
errors.append(f"State '{file_info['State']}' is not valid. Please add it.")
if state_data:
cursor.callproc('GetDistrictByNameAndStates', [file_info['District'], state_data['State_ID']])
cursor.callproc('GetDistrictByNameAndState', [file_info['District'], state_data['State_Id']]) # Change GetDistrictByNameAndStates to GetDistrictByNameAndState
for result in cursor.stored_results():
district_data = result.fetchone()
if not district_data:
errors.append(f"District '{file_info['District']}' is not valid under state '{file_info['State']}'.")
if district_data:
cursor.callproc('GetBlockByNameAndDistricts', [file_info['Block'], district_data['District_ID']])
cursor.callproc('GetBlockByNameAndDistrict', [file_info['Block'], district_data['District_id']]) #Change District_ID to District_id and GetBlockByNameAndDistricts to GetBlockByNameAndDistrict
for result in cursor.stored_results():
block_data = result.fetchone()
if not block_data:
@@ -99,7 +84,9 @@ def show_table(filename):
subcontractor_data = result.fetchone()
if not subcontractor_data:
cursor.callproc('InsertSubcontractor', [file_info['Subcontractor']])
# cursor.callproc('InsertSubcontractor', [file_info['Subcontractor']])
# connection.commit()
cursor.callproc('SaveContractor', [file_info.get('Subcontractor'),None,None,None,None,None,None,None,None])
connection.commit()
cursor.callproc('GetSubcontractorByName', [file_info['Subcontractor']])
for result in cursor.stored_results():
@@ -244,7 +231,7 @@ def save_data():
else:
work_type = " ".join(words[:work_pos + 1])
if Invoice_Details and 'village' in Invoice_Details.lower() and 'work' in Invoice_Details.lower():
print("village_name ::", village_name, "|| work_type ::", work_type)
# print("village_name ::", village_name, "|| work_type ::", work_type)
if block_id and village_name:
village_id = None
cursor.callproc("GetVillageId", (block_id, village_name))
@@ -257,11 +244,11 @@ def save_data():
for result in cursor.stored_results():
result = result.fetchone()
village_id = result[0] if result else None
print("village_id :", village_id)
print("block_id :", block_id)
print("invoice :", PMC_No, village_id, work_type, Invoice_Details, Invoice_Date, Invoice_No,
Basic_Amount, Debit_Amount, After_Debit_Amount, Amount, GST_Amount, TDS_Amount,
SD_Amount, On_Commission, Hydro_Testing, GST_SD_Amount, Final_Amount)
# print("village_id :", village_id)
# print("block_id :", block_id)
# print("invoice :", PMC_No, village_id, work_type, Invoice_Details, Invoice_Date, Invoice_No,
# Basic_Amount, Debit_Amount, After_Debit_Amount, Amount, GST_Amount, TDS_Amount,
# SD_Amount, On_Commission, Hydro_Testing, GST_SD_Amount, Final_Amount)
args = (
PMC_No, village_id, work_type, Invoice_Details, Invoice_Date, Invoice_No,
@@ -270,22 +257,39 @@ def save_data():
subcontractor_id, 0
)
print("All invoice Details ",args)
# print("All invoice Details ",args)
# add subcontarctor id in invoice table
results = cursor.callproc('SaveInvoice', args)
invoice_id = results[-1]
print("invoice id from the excel ", invoice_id)
print("**************************************************************")
print(invoice_id)
print("**************************************************************")
cursor.callproc(
"SavePayment",
(
PMC_No,
Invoice_No, # required
Payment_Amount,
TDS_Payment_Amount,
Total_Amount,
UTR,
invoice_id # last
)
)
# print("invoice id from the excel ", invoice_id)
if isinstance(hold_columns, str):
hold_columns = ast.literal_eval(hold_columns)
if isinstance(hold_columns, list) and all(isinstance(hold, dict) for hold in hold_columns):
for hold in hold_columns:
print(f"Processing hold: {hold}")
# print(f"Processing hold: {hold}")
hold_column_name = hold.get('column_name') # Get column name
hold_type_id = hold.get('hold_type_id') # Get hold_type_id
if hold_column_name:
hold_amount = entry.get(
hold_column_name) # Get the value for that specific hold column
if hold_amount is not None:
print(f"Processing hold type: {hold_column_name}, Hold Amount: {hold_amount}")
# print(f"Processing hold type: {hold_column_name}, Hold Amount: {hold_amount}")
hold_join_data = {
"Contractor_Id": subcontractor_id,
"Invoice_Id": invoice_id,
@@ -304,8 +308,8 @@ def save_data():
print("Hold columns data is not a valid list of dictionaries.")
#---------------------------------------------Credit Note---------------------------------------------------------------------------
elif any(keyword in Invoice_Details.lower() for keyword in ['credit note','logging report']):
print("Credit note found:", PMC_No, Invoice_No, Basic_Amount, Debit_Amount, Final_Amount,
After_Debit_Amount, GST_Amount, Amount, Final_Amount, Payment_Amount, Total_Amount, UTR, Invoice_No)
# print("Credit note found:", PMC_No, Invoice_No, Basic_Amount, Debit_Amount, Final_Amount,
# After_Debit_Amount, GST_Amount, Amount, Final_Amount, Payment_Amount, Total_Amount, UTR, Invoice_No)
cursor.callproc(
'AddCreditNoteFromExcel',
[
@@ -330,52 +334,108 @@ def save_data():
]
# Step 3: Matching condition
if any(kw in normalized_details for kw in keywords):
print("✅ Match found. Inserting hold release for:", Invoice_Details)
# print("✅ Match found. Inserting hold release for:", Invoice_Details)
cursor.callproc(
'AddHoldReleaseFromExcel',
[PMC_No, Invoice_No, Invoice_Details, Basic_Amount, Final_Amount, UTR, subcontractor_id]
)
connection.commit()
print("✅ Hold release inserted for:", PMC_No, Invoice_Details)
# print("✅ Hold release inserted for:", PMC_No, Invoice_Details)
#------------------------------------------------------------------------------------------------------------------
elif Invoice_Details and any(
keyword in Invoice_Details.lower() for keyword in ['gst', 'release', 'note']):
print("Gst rels :", PMC_No, Invoice_No, Basic_Amount, Final_Amount,Total_Amount,UTR, subcontractor_id)
keyword in Invoice_Details.lower() for keyword in ['gst', 'release', 'gst release note']):
# print("Gst rels :", PMC_No, Invoice_No, Basic_Amount, Final_Amount,Total_Amount,UTR, subcontractor_id)
cursor.callproc(
'AddGSTReleaseFromExcel',
[PMC_No, Invoice_No, Basic_Amount, Final_Amount, Total_Amount, UTR, subcontractor_id]
)
if PMC_No and Total_Amount and UTR:
print("Payment :", PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR )
cursor.callproc("SavePayment",(PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR ))
if not village_id:
village_id = None
cursor.callproc('InsertOrUpdateInPayment', (
PMC_No,
village_id,
work_type,
Invoice_Details,
Invoice_Date,
Invoice_No,
Basic_Amount,
Debit_Amount,
After_Debit_Amount,
Amount,
GST_Amount,
TDS_Amount,
SD_Amount,
On_Commission,
Hydro_Testing,
0,
GST_SD_Amount,
Final_Amount,
Payment_Amount,
TDS_Payment_Amount,
Total_Amount,
UTR,
subcontractor_id
))
# --------------------------------------
# If no village/work detected, only PMC/Payment
if not (Invoice_Details and 'village' in Invoice_Details.lower() and 'work' in Invoice_Details.lower()):
# if not (Invoice_Details and 'village' in Invoice_Details.lower() and 'work' in Invoice_Details.lower() and 'gst' in Invoice_Details.lower() and 'gst release note' in Invoice_Details.lower() and 'release' in Invoice_Details.lower()):
# ---------- Only PMC / Payment rows ----------
if PMC_No and not Invoice_No and UTR :
# print("No village/work, using PMC only :", PMC_No)
# check invoice exists
# cursor.execute(
# "SELECT invoice_id FROM invoice WHERE PMC_No=%s ORDER BY invoice_id DESC LIMIT 1",
# (PMC_No,)
# )
# row = cursor.fetchone()
# invoice_id = row[0] if row else None
# # insert invoice if not exists
# if not invoice_id:
print(" extra payment :", PMC_No,Total_Amount,UTR, subcontractor_id)
# cursor.execute(
# """
# INSERT INTO invoice (PMC_No,Contractor_Id) VALUES (%s, %s);
# """,
# (PMC_No, subcontractor_id)
# )
# connection.commit()
# cursor.execute(
# "SELECT invoice_id FROM invoice WHERE PMC_No=%s AND Contractor_Id =%s ORDER BY invoice_id DESC LIMIT 1",
# (PMC_No, subcontractor_id)
# )
# row = cursor.fetchone()
cursor.callproc("insertExtrapaymet",(PMC_No, subcontractor_id))
for result in cursor.stored_results():
row = result.fetchone()
invoice_id = row[0] if row else None
# insert payment
cursor.callproc(
"SavePayment",
(
PMC_No,
Invoice_No, # required
Payment_Amount,
TDS_Payment_Amount,
Total_Amount,
UTR,
invoice_id
)
)
# if PMC_No and Total_Amount and UTR:
# print("Payment :", PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR )
# Add inoice id in payment table
# cursor.callproc("SavePayment",(PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR, invoice_id))
# if not village_id:
# village_id = None
# cursor.callproc('InsertOrUpdateInPayment', (
# PMC_No,
# village_id,
# work_type,
# Invoice_Details,
# Invoice_Date,
# Invoice_No,
# Basic_Amount,
# Debit_Amount,
# After_Debit_Amount,
# Amount,
# GST_Amount,
# TDS_Amount,
# SD_Amount,
# On_Commission,
# Hydro_Testing,
# 0,
# GST_SD_Amount,
# Final_Amount,
# Payment_Amount,
# TDS_Payment_Amount,
# Total_Amount,
# UTR,f
# subcontractor_id
# ))
connection.commit()
return jsonify({"success": "Data saved successfully!"}), 200
except Exception as e:

View File

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

View File

@@ -5,32 +5,32 @@ from model.GST import GST
hold_bp = Blueprint("hold_types", __name__)
hold = HoldTypes()
# ---------------- ADD HOLD TYPE ----------------
@hold_bp.route('/add_hold_type', methods=['GET','POST'])
@login_required
def add_hold_type():
hold = HoldTypes()
# hold = HoldTypes()
if request.method == 'POST':
hold.AddHoldType(request) # ✅
return hold.resultMessage
hold.AddHoldType(request)
# ✅ Always redirect to same page (NO JSON)
return redirect(url_for("hold_types.add_hold_type"))
hold_types = hold.GetAllHoldTypes() # ✅
# GET request → show data
hold_types = hold.GetAllHoldTypes()
return render_template(
"add_hold_type.html",
Hold_Types_data=hold_types
)
# ---------------- CHECK HOLD TYPE (OPTIONAL LIKE BLOCK) ----------------
@hold_bp.route('/check_hold_type', methods=['POST'])
@login_required
def check_hold_type():
hold = HoldTypes()
# hold = HoldTypes()
return hold.CheckHoldType(request) # if exists
@@ -39,7 +39,7 @@ def check_hold_type():
@login_required
def edit_hold_type(id):
hold = HoldTypes()
# hold = HoldTypes()
if request.method == 'POST':
hold.EditHoldType(request, id) # ✅
@@ -58,7 +58,7 @@ def edit_hold_type(id):
@login_required
def delete_hold_type(id):
hold = HoldTypes()
# hold = HoldTypes()
hold.DeleteHoldType(request, id) # ✅
return redirect(url_for("hold_types.add_hold_type"))

View File

@@ -1,6 +1,3 @@
# controllers/invoice_controller.py
from flask import Blueprint, request, jsonify, render_template
@@ -40,7 +37,11 @@ def add_invoice():
village_id = village_result['Village_Id']
invoice_id = insert_invoice(data, village_id)
assign_subcontractor(data, village_id)
# assign_subcontractor(data, village_id)
print("********************************************************************")
print("Manully added invoice id :",invoice_id)
print("********************************************************************")
insert_hold_types(data, invoice_id)
log_action("Add invoice", f"added invoice '{data.get('pmc_no')}'")
@@ -83,7 +84,7 @@ def edit_invoice(invoice_id):
if request.method == 'POST':
data = request.form
update_invoice(data, invoice_id)
update_inpayment(data)
# update_inpayment(data)
log_action("Edit invoice", f"edited invoice '{invoice_id}'")
return jsonify({"status": "success", "message": "Invoice updated successfully"}), 200

View File

@@ -21,7 +21,6 @@ def activity_log():
end_date,
user_name
)
return render_template(
"activity_log.html",
logs=filtered_logs,

View File

@@ -1,4 +1,4 @@
from flask import Blueprint, render_template, request, redirect, url_for, jsonify
from flask import Blueprint, render_template, request, redirect, url_for, jsonify, flash
from flask_login import login_required, current_user
from model.payment import Paymentmodel
from model.Log import LogHelper
@@ -28,8 +28,8 @@ def add_payment():
utr = request.form['utr']
LogHelper.log_action("Add Payment", f"User {current_user.id} Add Payment '{pmc_no}'")
Paymentmodel.insert_payment(pmc_no, invoice_no, amount, tds_amount, total_amount, utr)
Paymentmodel.update_inpayment(subcontractor_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr)
Paymentmodel.insert_payment(subcontractor_id,pmc_no, invoice_no, amount, tds_amount, total_amount, utr)
# Paymentmodel.update_inpayment(subcontractor_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr)
return redirect(url_for('payment_bp.add_payment'))
@@ -72,32 +72,28 @@ def edit_payment(payment_id):
Paymentmodel.call_update_payment_proc(payment_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr)
# Update inpayment
connection = Paymentmodel.get_connection()
cursor = connection.cursor()
cursor.callproc(
'UpdateInpaymentByPMCInvoiceUTR',
[amount, tds_amount, total_amount, pmc_no, invoice_no, utr]
)
connection.commit()
cursor.close()
connection.close()
# connection = Paymentmodel.get_connection()
# cursor = connection.cursor()
# cursor.callproc('UpdateInpaymentByPMCInvoiceUTR',[amount, tds_amount, total_amount, pmc_no, invoice_no, utr])
# connection.commit()
# cursor.close()
# connection.close()
return redirect(url_for('payment_bp.add_payment'))
return render_template('edit_payment.html', payment_data=payment_data)
# ------------------- Delete Payment -------------------
@payment_bp.route('/delete_payment/<int:payment_id>', methods=['GET', 'POST'])
@payment_bp.route('/delete_payment/<int:payment_id>', methods=['GET'])
@login_required
def delete_payment(payment_id):
success, pmc_no, invoice_no = Paymentmodel.delete_payment(payment_id)
if not success:
return jsonify({"message": "Payment not found or failed to delete", "status": "error"}), 404
flash("Payment not found or failed to delete", "error")
else:
LogHelper.log_action("Delete Payment", f"User {current_user.id} deleted Payment '{payment_id}'")
flash(f"Payment ID {payment_id} deleted successfully.", "success")
LogHelper.log_action("Delete Payment", f"User {current_user.id} deleted Payment '{payment_id}'")
return jsonify({
"message": f"Payment ID {payment_id} deleted successfully.",
"status": "success"
}), 200
return redirect(url_for('payment_bp.add_payment'))

View File

@@ -1,37 +1,40 @@
from flask import Blueprint, render_template, send_from_directory
from flask_login import login_required, current_user
from model.PmcReport import PmcReport
# from flask import Blueprint, render_template, send_from_directory
# from flask_login import login_required
# 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>")
@login_required
def pmc_report(pmc_no):
data = PmcReport.get_pmc_report(pmc_no)
if not data:
return "No PMC found with this number", 404
# # ---------------- Contractor Report by pmc no ----------------
# @pmc_report_bp.route("/pmc_report/<pmc_no>")
# @login_required
# def pmc_report(pmc_no):
# data = PmcReport.get_pmc_report(pmc_no)
# if not data:
# return "No PMC found with this number", 404
return render_template(
"pmc_report.html",
info=data["info"],
invoices=data["invoices"],
hold_types=data["hold_types"],
gst_rel=data["gst_rel"],
payments=data["payments"],
credit_note=data["credit_note"],
hold_release=data["hold_release"],
total=data["total"]
)
# return render_template(
# "pmc_report.html",
# info=data["info"],
# invoices=data["invoices"],
# hold_types=data["hold_types"],
# gst_rel=data["gst_rel"],
# payments=data["payments"],
# credit_note=data["credit_note"],
# hold_release=data["hold_release"],
# total=data["total"]
# )
@pmc_report_bp.route("/download_pmc_report/<pmc_no>")
@login_required
def download_pmc_report(pmc_no):
# # ---------------- Contractor Download Report by pmc no ----------------
# @pmc_report_bp.route("/download_pmc_report/<pmc_no>")
# @login_required
# def download_pmc_report(pmc_no):
result = PmcReport.download_pmc_report(pmc_no)
# result = PmcReport.download_pmc_report(pmc_no)
if not result:
return "No contractor found for this PMC No", 404
# if not result:
# return "No contractor found for this PMC No", 404
output_folder, file_name = result
# output_folder, file_name = result
# return send_from_directory(output_folder, file_name, as_attachment=True)
return send_from_directory(output_folder, file_name, as_attachment=True)

View File

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

View File

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

View File

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

View File

@@ -11,15 +11,15 @@ from model.State import State
# Create Blueprint
village_bp = Blueprint('village', __name__)
village = Village()
# ------------------------- Add Village -------------------------
@village_bp.route('/add_village', methods=['GET', 'POST'])
@login_required
def add_village():
village = Village()
# village = Village()
if request.method == 'POST':
village.AddVillage(request=request)
return village.resultMessage
@@ -79,28 +79,40 @@ def get_blocks(district_id):
@village_bp.route('/check_village', methods=['POST'])
@login_required
def check_village():
village = 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 = Village()
village.DeleteVillage(request=request, village_id=village_id)
flash(village.resultMessage, "success" if village.isSuccess else "error")
return redirect(url_for('village.add_village'))
# ✅ Convert resultMessage to string if it's a Response or tuple
raw_msg = village.resultMessage
if isinstance(raw_msg, tuple):
# e.g., (<Response ...>, 200)
msg = "Village deleted successfully!"
elif hasattr(raw_msg, 'get_data'):
# Flask Response object
msg = raw_msg.get_data(as_text=True) # get raw text
else:
# fallback
msg = str(raw_msg) if raw_msg else "Village deleted successfully!"
return jsonify({
"status": "success" if village.isSuccess else "error",
"message": msg
})
# ------------------------- Edit Village -------------------------
@village_bp.route('/edit_village/<int:village_id>', methods=['GET', 'POST'])
@login_required
def edit_village(village_id):
village = Village()
# village = Village()
if request.method == 'POST':

View File

@@ -16,7 +16,7 @@ from controllers.payment_controller import payment_bp
from controllers.gst_release_controller import gst_release_bp
from controllers.excel_upload_controller import excel_bp
from controllers.report_controller import report_bp
from controllers.pmc_report_controller import pmc_report_bp
# from controllers.pmc_report_controller import pmc_report_bp
from controllers.hold_types_controller import hold_bp
from dotenv import load_dotenv
@@ -57,7 +57,7 @@ app.register_blueprint(payment_bp)
app.register_blueprint(gst_release_bp)
app.register_blueprint(excel_bp)
app.register_blueprint(report_bp)
app.register_blueprint(pmc_report_bp)
# app.register_blueprint(pmc_report_bp)
app.register_blueprint(hold_bp)
# ---------------- Run App ----------------

View File

@@ -1,20 +1,6 @@
from flask import Flask, render_template, request, redirect, url_for, send_from_directory, flash, jsonify, json
from flask import current_app
from datetime import datetime
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from model.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType
from model.Log import LogData, LogHelper
import os
import config
import re
import mysql.connector
from mysql.connector import Error
from model.ItemCRUD import ItemCRUD, itemCRUDMapping
from model.ItemCRUD import ItemCRUD
class Block:
@@ -26,9 +12,7 @@ class Block:
self.isSuccess = False
self.resultMessage = ""
# ----------------------------------------------------------
# Add Block
# ----------------------------------------------------------
def AddBlock(self, request):
block = ItemCRUD(itemType=ItemCRUDType.Block)
@@ -41,17 +25,7 @@ class Block:
self.resultMessage = block.resultMessage
return
# ----------------------------------------------------------
# Get All Blocks
# ----------------------------------------------------------
# def GetAllBlocks(self):
# block = ItemCRUD(itemType=ItemCRUDType.Block)
# blocksdata = block.GetAllData(request=request, storedproc="GetAllBlock")
# self.isSuccess = block.isSuccess
# self.resultMessage = block.resultMessage
# return blocksdata
# Get All Blocks
def GetAllBlocks(self, request):
block = ItemCRUD(itemType=ItemCRUDType.Block)
@@ -61,18 +35,8 @@ class Block:
self.resultMessage = block.resultMessage
return blocksdata
# ----------------------------------------------------------
# Check Block Exists
# ----------------------------------------------------------
# def CheckBlock(self, request):
# block = ItemCRUD(itemType=ItemCRUDType.Block)
# block_name = request.json.get('block_Name', '').strip()
# district_id = request.json.get('district_Id')
# result = block.CheckItem(request=request, parentid=district_id, childname=block_name, storedprocfetch="GetBlockByNameAndDistrict")
# self.isSuccess = block.isSuccess
# self.resultMessage = block.resultMessage
# return result
def CheckBlock(self, request):
block = ItemCRUD(itemType=ItemCRUDType.Block)
data = request.get_json(silent=True) or request.form
@@ -89,24 +53,7 @@ class Block:
self.resultMessage = block.resultMessage
return result
# ----------------------------------------------------------
# Get Block By ID
# ----------------------------------------------------------
# def GetBlockByID(self, id):
# block = ItemCRUD(itemType=ItemCRUDType.Village)
# blockdata = block.GetAllData(id=id,storedproc="GetBlockDataByID")
# self.isSuccess = block.isSuccess
# self.resultMessage = block.resultMessage
# print("akash"+blockdata)
# return blockdata
# def GetBlockByID(self,request,id):
# block = ItemCRUD(itemType=ItemCRUDType.Block)
# blockdata = block.GetDataByID(request=request,id=id,storedproc="GetBlockDataByID")
# self.isSuccess = block.isSuccess
# self.resultMessage = block.resultMessage
# return blockdata
def GetBlockByID(self, id):
block = ItemCRUD(itemType=ItemCRUDType.Block)
@@ -120,20 +67,8 @@ class Block:
self.resultMessage = block.resultMessage
return blockdata
# ----------------------------------------------------------
# Update Block
# ----------------------------------------------------------
# def EditBlock(self, request, block_id):
# block = ItemCRUD(itemType=ItemCRUDType.Block)
# district_id = request.form.get('district_Id')
# block_name = request.form.get('block_Name', '').strip()
# block.EditItem(request=request, childid=block_id, parentid=district_id, childname=block_name, storedprocadd="UpdateBlockById" )
# self.isSuccess = block.isSuccess
# self.resultMessage = block.resultMessage
# return
def EditBlock(self, request, block_id):
block = ItemCRUD(itemType=ItemCRUDType.Block)
@@ -151,11 +86,10 @@ class Block:
self.isSuccess = block.isSuccess
self.resultMessage = block.resultMessage
return render_template('add_block.html')
return
# ----------------------------------------------------------
# Delete Block
# ---------------------------------------------------------
# Delete Block
def DeleteBlock(self,request, id):
block = ItemCRUD(itemType=ItemCRUDType.Block)

View File

@@ -1,10 +1,5 @@
from mysql.connector import Error
import config
from datetime import datetime
class ContractorInfo:
def __init__(self, contractor_id):

View File

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

View File

@@ -27,13 +27,27 @@ class FolderAndFile:
os.makedirs(folder, exist_ok=True)
return folder
# -----------------------------
# FILE PATH METHODS
# -----------------------------
@staticmethod
def get_logs_folder():
folder = os.path.join(current_app.root_path, "logs")
if not os.path.exists(folder):
os.makedirs(folder)
os.makedirs(folder, exist_ok=True)
return folder
# FILE PATH METHODS - download
@staticmethod
def get_download_path(filename):
return os.path.join(FolderAndFile.get_download_folder(), filename)
# FILE PATH METHODS - upload file
@staticmethod
def get_upload_path(filename):
return os.path.join(FolderAndFile.get_upload_folder(), filename)
return os.path.join(FolderAndFile.get_upload_folder(), filename)
# FILE PATH METHODS - activity log file
@staticmethod
def get_activity_log_path(filename):
return os.path.join(FolderAndFile.get_logs_folder(), filename)

View File

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

View File

@@ -3,7 +3,6 @@ from model.ItemCRUD import ItemCRUD
from model.Utilities import ItemCRUDType
class HoldTypes:
"""CRUD operations for Hold Types using ItemCRUD"""
def __init__(self):
self.isSuccess = False
@@ -33,7 +32,7 @@ class HoldTypes:
self.isSuccess = hold.isSuccess
self.resultMessage = hold.resultMessage
# Convert tuple → dictionary
# Convert tuple → dictionary
data = []
for row in rows:
data.append({
@@ -51,7 +50,7 @@ class HoldTypes:
self.isSuccess = hold.isSuccess
self.resultMessage = hold.resultMessage
# Convert tuple → dictionary
# Convert tuple → dictionary
if row:
return {
"hold_type_id": row[0],

View File

@@ -66,27 +66,27 @@ def get_all_villages():
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')
# 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),
# data.get('subcontractor_id')
# Insert inpayment
cursor.callproc('InsertInpayment', [
# ])
# invoice_row = fetch_one(cursor)
# if not invoice_row:
# raise Exception("Invoice ID not returned")
# invoice_id = invoice_row.get('invoice_id')
cursor.callproc('SaveInvoice', [
data.get('pmc_no'),
village_id,
data.get('work_type'),
@@ -94,9 +94,27 @@ def insert_invoice(data, village_id):
data.get('invoice_date'),
data.get('invoice_no'),
*get_numeric_values(data),
data.get('subcontractor_id')
data.get('subcontractor_id'),
0
])
clear_results(cursor)
invoice_id = None
for result in cursor.stored_results():
row = result.fetchone()
if row:
invoice_id = row['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)
@@ -141,18 +159,18 @@ def update_invoice(data, invoice_id):
clear_results(cursor)
execute_db_operation(operation)
def update_inpayment(data):
def operation(cursor):
cursor.callproc('UpdateInpayment', [
data.get('work_type'),
data.get('invoice_details'),
data.get('invoice_date'),
*get_numeric_values(data),
data.get('pmc_no'),
data.get('invoice_no')
])
clear_results(cursor)
execute_db_operation(operation)
# def update_inpayment(data):
# def operation(cursor):
# cursor.callproc('UpdateInpayment', [
# data.get('work_type'),
# data.get('invoice_details'),
# data.get('invoice_date'),
# *get_numeric_values(data),
# data.get('pmc_no'),
# data.get('invoice_no')
# ])
# clear_results(cursor)
# execute_db_operation(operation)
def delete_invoice_data(invoice_id, user_id):
def operation(cursor):
@@ -173,22 +191,22 @@ def delete_invoice_data(invoice_id, user_id):
clear_results(cursor)
# Delete inpayment
cursor.callproc('DeleteInpaymentByPMCInvoice', (pmc_no, invoice_no))
clear_results(cursor)
# cursor.callproc('DeleteInpaymentByPMCInvoice', (pmc_no, invoice_no))
# clear_results(cursor)
execute_db_operation(operation)
# ------------------- Subcontractor Functions -------------------
def assign_subcontractor(data, village_id):
def operation(cursor):
cursor.callproc('AssignSubcontractor', [
data.get('pmc_no'),
data.get('subcontractor_id'),
village_id
])
clear_results(cursor)
execute_db_operation(operation)
# def assign_subcontractor(data, village_id):
# def operation(cursor):
# cursor.callproc('AssignSubcontractor', [
# data.get('pmc_no'),
# data.get('subcontractor_id'),
# village_id
# ])
# clear_results(cursor)
# execute_db_operation(operation)
# ------------------- Hold Types Functions -------------------

View File

@@ -6,7 +6,6 @@ import config
import re
import mysql.connector
# ----------------------------------------------------------
# Mapping Class
# ----------------------------------------------------------
@@ -23,10 +22,11 @@ class itemCRUDMapping:
self.name = "Hold Type"
elif itemType is ItemCRUDType.Subcontractor:
self.name = "Subcontractor"
elif itemType.name == "GSTRelease":
self.name = "GSTRelease"
else:
self.name = "Item"
# ----------------------------------------------------------
# Generic CRUD Class
# ----------------------------------------------------------
@@ -93,13 +93,47 @@ class ItemCRUD:
try:
# ======================================================
# SUBCONTRACTOR (MULTI-FIELD)
# GSTRelease MULTI-FIELD
# ======================================================
if data:
if self.itemCRUDType.name == "GSTRelease" and data:
# Duplicate check (PMC_No + Invoice_No)
if storedprocfetch:
cursor.callproc(storedprocfetch, (data['PMC_No'], data['Invoice_No']))
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 GSTRelease
cursor.callproc(storedprocadd, (
data['PMC_No'],
data['Invoice_No'],
data['Basic_Amount'],
data['Final_Amount'],
data['Total_Amount'],
data['UTR'],
data['Contractor_ID']
))
connection.commit()
self.isSuccess = True
self.resultMessage = HtmlHelper.json_response(
ResponseHandler.add_success(self.itemCRUDMapping.name), 200
)
return
# ======================================================
# SUBCONTRACTOR MULTI-FIELD
# ======================================================
if self.itemCRUDType.name == "Subcontractor" and data:
# Duplicate check
cursor.callproc(storedprocfetch, (data['Contractor_Name'],))
existing_item = None
for rs in cursor.stored_results():
existing_item = rs.fetchone()
@@ -111,7 +145,6 @@ class ItemCRUD:
)
return
# Insert
cursor.callproc(storedprocadd, (
data['Contractor_Name'],
data['Address'],
@@ -123,26 +156,24 @@ class ItemCRUD:
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)
# NORMAL SINGLE-FIELD (Village / Block / State)
# ======================================================
if not re.match(RegEx.patternAlphabetOnly, childname):
if not re.match(RegEx.allPattern, childname):
self.isSuccess = False
self.resultMessage = HtmlHelper.json_response(
ResponseHandler.invalid_name(self.itemCRUDMapping.name), 400
)
return
# Duplicate check
if parentid is None:
cursor.callproc(storedprocfetch, (childname,))
else:
@@ -159,17 +190,14 @@ class ItemCRUD:
)
return
# Insert
if parentid is None:
cursor.callproc(storedprocadd, (childname,))
else:
cursor.callproc(storedprocadd, (childname, parentid))
connection.commit()
self.isSuccess = True
self.resultMessage = HtmlHelper.json_response(
ResponseHandler.add_success(self.itemCRUDMapping.name), 200
)
@@ -199,9 +227,32 @@ class ItemCRUD:
try:
# ======================================================
# SUBCONTRACTOR (MULTI-FIELD)
# GSTRelease MULTI-FIELD
# ======================================================
if data:
if self.itemCRUDType.name == "GSTRelease" and data:
cursor.callproc(storedprocupdate, (
data['p_pmc_no'], # PMC_No
data['p_invoice_no'], # Invoice_No
data['p_basic_amount'], # Basic_Amount
data['p_final_amount'], # Final_Amount
data['p_total_amount'], # Total_Amount
data['p_utr'], # UTR
data['p_gst_release_id']# GST_Release_Id
))
connection.commit()
self.isSuccess = True
self.resultMessage = HtmlHelper.json_response(
ResponseHandler.update_success(self.itemCRUDMapping.name), 200
)
return
# ======================================================
# SUBCONTRACTOR MULTI-FIELD
# ======================================================
if self.itemCRUDType.name == "Subcontractor" and data:
cursor.callproc(storedprocupdate, (
childid,
data['Contractor_Name'],
@@ -214,9 +265,7 @@ class ItemCRUD:
data['GST_No'],
data['Contractor_password']
))
connection.commit()
self.isSuccess = True
self.resultMessage = HtmlHelper.json_response(
ResponseHandler.update_success(self.itemCRUDMapping.name), 200
@@ -224,9 +273,9 @@ class ItemCRUD:
return
# ======================================================
# NORMAL
# NORMAL SINGLE-FIELD
# ======================================================
if not re.match(RegEx.patternAlphabetOnly, childname):
if not re.match(RegEx.allPattern, childname):
self.isSuccess = False
self.resultMessage = ResponseHandler.update_failure(self.itemCRUDMapping.name)['message']
return
@@ -237,7 +286,6 @@ class ItemCRUD:
cursor.callproc(storedprocupdate, (childid, parentid, childname))
connection.commit()
self.isSuccess = True
self.resultMessage = ResponseHandler.update_success(self.itemCRUDMapping.name)['message']
@@ -259,20 +307,15 @@ class ItemCRUD:
data = []
connection = config.get_db_connection()
if not connection:
return []
cursor = connection.cursor()
try:
cursor.callproc(storedproc)
for result in cursor.stored_results():
data = result.fetchall()
self.isSuccess = True
except mysql.connector.Error as e:
print(f"Error fetching {self.itemCRUDMapping.name}: {e}")
self.isSuccess = False
@@ -280,7 +323,6 @@ class ItemCRUD:
ResponseHandler.fetch_failure(self.itemCRUDMapping.name), 500
)
return []
finally:
cursor.close()
connection.close()
@@ -298,13 +340,10 @@ class ItemCRUD:
try:
cursor.callproc(storedproc, (id,))
for rs in cursor.stored_results():
data = rs.fetchone()
except mysql.connector.Error as e:
print(f"Error fetching {self.itemCRUDMapping.name}: {e}")
finally:
cursor.close()
connection.close()
@@ -324,7 +363,7 @@ class ItemCRUD:
f"User {current_user.id} checked '{childname}'"
)
if not re.match(RegEx.patternAlphabetOnly, childname):
if not re.match(RegEx.allPattern, childname):
return HtmlHelper.json_response(
ResponseHandler.invalid_name(self.itemCRUDMapping.name), 400
)
@@ -353,7 +392,6 @@ class ItemCRUD:
return HtmlHelper.json_response(
ResponseHandler.fetch_failure(self.itemCRUDMapping.name), 500
)
finally:
cursor.close()
connection.close()

View File

@@ -1,10 +1,9 @@
from flask import Flask, render_template, request, redirect, url_for, send_from_directory, flash, jsonify, json
from flask import current_app
from datetime import datetime
import os
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
import os
from datetime import datetime
from model.FolderAndFile import FolderAndFile
class LogHelper:
@staticmethod
@@ -14,22 +13,24 @@ class LogHelper:
logData.WriteLog(action, details="")
class LogData:
filepath = ""
timestamp = None
def __init__(self):
self.filepath = os.path.join(current_app.root_path, 'activity.log')
self.filepath = FolderAndFile.get_activity_log_path('activity.log')
self.timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.user = LogData.get_current_user()
@staticmethod
def get_current_user():
if hasattr(current_user, "cn") and current_user.cn:
self.user = current_user.cn
return current_user.cn
elif hasattr(current_user, "username") and current_user.username:
self.user = current_user.username
return current_user.username
elif hasattr(current_user, "sAMAccountName") and current_user.sAMAccountName:
self.user = current_user.sAMAccountName
else:
self.user = "Unknown"
return current_user.sAMAccountName
return "Unknown"
def WriteLog(self, action, details=""):
"""Log user actions with timestamp, user, action, and details."""
@@ -42,7 +43,6 @@ class LogData:
f"Details: {details}\n"
)
def GetActivitiesLog(self):
logs = []
@@ -60,7 +60,6 @@ class LogData:
return logs
def GetFilteredActivitiesLog(self, startDate, endDate, userName):
filtered_logs = self.GetActivitiesLog()
# Date filter
@@ -69,17 +68,14 @@ class LogData:
start_dt = datetime.strptime(startDate, "%Y-%m-%d") if startDate else datetime.min
end_dt = datetime.strptime(endDate, "%Y-%m-%d") if endDate else datetime.max
filtered_logs = [
log for log in filtered_logs
if start_dt <= datetime.strptime(log["timestamp"], "%Y-%m-%d %H:%M:%S") <= end_dt
]
except Exception as e:
print("Date filter error:", e)
#Why catching all exceptions? Need to handle specific exceptions
# Username filter
if userName:
filtered_logs = [log for log in filtered_logs if userName.lower() in log["user"].lower()]

View File

@@ -1,456 +1,137 @@
import openpyxl
from openpyxl.styles import Font, PatternFill
import config
from flask_login import current_user
from model.Log import LogHelper
from model.Report import ReportHelper
from services.Generalservice import GeneralUse
from model.FolderAndFile import FolderAndFile
from model.Report import ReportHelper
class PmcReport:
data=[]
@staticmethod
def get_pmc_report(pmc_no):
# @staticmethod
# def get_pmc_report(pmc_no):
connection = config.get_db_connection()
cursor = connection.cursor(dictionary=True, buffered=True)
# connection = config.get_db_connection()
# cursor = connection.cursor(dictionary=True, buffered=True)
try:
# try:
# pmc_info = GeneralUse.execute_sp(cursor, 'GetContractorInfoByPmcNo', [pmc_no], True)
# cursor.callproc("Get_pmc_hold_types", (pmc_no, pmc_info["Contractor_Id"]))
# hold_types = next(cursor.stored_results()).fetchall()
# cursor.callproc("GetContractorInfoByPmcNo", (pmc_no,))
# pmc_info = next(cursor.stored_results()).fetchone()
pmc_info = ReportHelper.execute_sp(cursor, 'GetContractorInfoByPmcNo', [pmc_no], True)
# # Extract hold_type_ids
# hold_type_ids = [ht['hold_type_id'] for ht in hold_types]
if not pmc_info:
return None
# invoices = []
# hold_type_ids_str = ",".join(map(str, hold_type_ids))
# cursor.callproc('GetInvoices_WithHold',[pmc_no, pmc_info["Contractor_Id"], hold_type_ids_str])
# for result in cursor.stored_results():
# invoices = result.fetchall()
cursor.callproc("Get_pmc_hold_types", (pmc_no, pmc_info["Contractor_Id"]))
hold_types = next(cursor.stored_results()).fetchall()
# Extract hold_type_ids
hold_type_ids = [ht['hold_type_id'] for ht in hold_types]
invoices = []
hold_amount_total = 0
if hold_type_ids:
hold_type_ids_str = ",".join(map(str, hold_type_ids))
cursor.callproc(
'GetInvoices_WithHold',
[pmc_no, pmc_info["Contractor_Id"], hold_type_ids_str]
)
else:
cursor.callproc(
'GetInvoices_NoHold',
[pmc_no, pmc_info["Contractor_Id"]]
)
for result in cursor.stored_results():
invoices = result.fetchall()
if hold_type_ids:
hold_amount_total = sum(row.get('hold_amount', 0) or 0 for row in invoices)
total_invo_final = sum(row.get('Final_Amount', 0) or 0 for row in invoices)
# GST RELEASE
# cursor.callproc('GetGSTReleaseByPMC', [pmc_no])
# gst_rel = []
# for result in cursor.stored_results():
# gst_rel = result.fetchall()
# gst_rel = GeneralUse.execute_sp(cursor, 'GetGSTReleaseByPMC', [pmc_no])
# hold_release = GeneralUse.execute_sp(cursor, 'GetHoldReleaseByPMC', [pmc_no])
gst_rel = ReportHelper.execute_sp(cursor, 'GetGSTReleaseByPMC', [pmc_no])
# credit_note = GeneralUse.execute_sp(cursor, 'GetCreditNoteByPMC', [pmc_no])
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)
# payments = GeneralUse.execute_sp(cursor, 'GetPaymentsByPMC', [pmc_no])
# totals = {
# "sum_invo_basic_amt": sum(row.get('Basic_Amount', 0) or 0 for row in invoices),
# "sum_invo_debit_amt": sum(row.get('Debit_Amount', 0) or 0 for row in invoices),
# "sum_invo_after_debit_amt": sum(row.get('After_Debit_Amount', 0) or 0 for row in invoices),
# "sum_invo_amt": sum(row.get('Amount', 0) or 0 for row in invoices),
# "sum_invo_gst_amt": sum(row.get('GST_Amount', 0) or 0 for row in invoices),
# "sum_invo_tds_amt": sum(row.get('TDS_Amount', 0) or 0 for row in invoices),
# "sum_invo_ds_amt": sum(row.get('SD_Amount', 0) or 0 for row in invoices),
# "sum_invo_on_commission": sum(row.get('On_Commission', 0) or 0 for row in invoices),
# "sum_invo_hydro_test": sum(row.get('Hydro_Testing', 0) or 0 for row in invoices),
# "sum_invo_gst_sd_amt": sum(row.get('GST_SD_Amount', 0) or 0 for row in invoices),
# "sum_invo_final_amt": sum(row.get('Final_Amount', 0) or 0 for row in invoices),
# "sum_invo_hold_amt": sum(row.get('hold_amount', 0) or 0 for row in invoices),
# "sum_gst_basic_amt": sum(row.get('basic_amount', 0) or 0 for row in gst_rel),
# "sum_gst_final_amt": sum(row.get('final_amount', 0) or 0 for row in gst_rel),
# "sum_pay_payment_amt": sum(row.get('Payment_Amount', 0) or 0 for row in payments),
# "sum_pay_tds_payment_amt": sum(row.get('TDS_Payment_Amount', 0) or 0 for row in payments),
# "sum_pay_total_amt": sum(row.get('Total_amount', 0) or 0 for row in payments)
# }
# ---------------- HOLD RELEASE ----------------
# cursor.callproc('GetHoldReleaseByPMC', [pmc_no])
# hold_release = []
# for result in cursor.stored_results():
# hold_release = result.fetchall()
# return {
# "info": pmc_info,
# "invoices": invoices,
# "hold_types": hold_types,
# "gst_rel": gst_rel,
# "payments": payments,
# "credit_note": credit_note,
# "hold_release": hold_release,
# "total": totals
# }
hold_release = ReportHelper.execute_sp(cursor, 'GetHoldReleaseByPMC', [pmc_no])
# finally:
# cursor.close()
# connection.close()
# ---------------- CREDIT NOTE ----------------
# cursor.callproc('GetCreditNoteByPMC', [pmc_no])
# credit_note = []
# for result in cursor.stored_results():
# credit_note = result.fetchall()
credit_note = ReportHelper.execute_sp(cursor, 'GetCreditNoteByPMC', [pmc_no])
payments = ReportHelper.execute_sp(cursor, 'GetPaymentsByPMC', [pmc_no])
# ---------------- PAYMENTS ----------------
# cursor.callproc('GetPaymentsByPMC', [pmc_no])
# payments = []
# for result in cursor.stored_results():
# payments = result.fetchall()
total_pay_amount = sum(row.get('Payment_Amount', 0) or 0 for row in payments)
total_pay_total = sum(row.get('Total_amount', 0) or 0 for row in payments)
totals = {
"sum_invo_basic_amt": sum(row.get('Basic_Amount', 0) or 0 for row in invoices),
"sum_invo_debit_amt": sum(row.get('Debit_Amount', 0) or 0 for row in invoices),
"sum_invo_after_debit_amt": sum(row.get('After_Debit_Amount', 0) or 0 for row in invoices),
"sum_invo_amt": sum(row.get('Amount', 0) or 0 for row in invoices),
"sum_invo_gst_amt": sum(row.get('GST_Amount', 0) or 0 for row in invoices),
"sum_invo_tds_amt": sum(row.get('TDS_Amount', 0) or 0 for row in invoices),
"sum_invo_ds_amt": sum(row.get('SD_Amount', 0) or 0 for row in invoices),
"sum_invo_on_commission": sum(row.get('On_Commission', 0) or 0 for row in invoices),
"sum_invo_hydro_test": sum(row.get('Hydro_Testing', 0) or 0 for row in invoices),
"sum_invo_gst_sd_amt": sum(row.get('GST_SD_Amount', 0) or 0 for row in invoices),
"sum_invo_final_amt": total_invo_final,
"sum_invo_hold_amt": hold_amount_total,
"sum_gst_basic_amt": total_gst_basic,
"sum_gst_final_amt": total_gst_final,
"sum_pay_payment_amt": total_pay_amount,
"sum_pay_tds_payment_amt": sum(row.get('TDS_Payment_Amount', 0) or 0 for row in payments),
"sum_pay_total_amt": total_pay_total
}
return {
"info": pmc_info,
"invoices": invoices,
"hold_types": hold_types,
"gst_rel": gst_rel,
"payments": payments,
"credit_note": credit_note,
"hold_release": hold_release,
"total": totals
}
finally:
cursor.close()
connection.close()
@staticmethod
def download_pmc_report(pmc_no):
connection = config.get_db_connection()
if not connection:
return None
cursor = connection.cursor(dictionary=True)
try:
# filename
filename = f"PMC_Report_{pmc_no}.xlsx"
output_folder = FolderAndFile.get_download_folder()
output_file = FolderAndFile.get_download_path(filename)
# ================= DATA FETCH =================
contractor_info = ReportHelper.execute_sp(cursor, 'GetContractorDetailsByPMC', [pmc_no], "one")
if not contractor_info:
return None
hold_types = ReportHelper.execute_sp(cursor, 'GetHoldTypesByContractor', [contractor_info["Contractor_Id"]])
hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types}
invoices = ReportHelper.execute_sp(cursor, 'GetInvoicesAndGstReleaseByPmcNo', [pmc_no])
credit_notes = ReportHelper.execute_sp(cursor, 'GetCreditNoteByContractor', [contractor_info["Contractor_Id"]])
hold_amounts = ReportHelper.execute_sp(cursor, 'GetHoldAmountsByContractor', [contractor_info["Contractor_Id"]])
all_payments = ReportHelper.execute_sp(cursor, 'GetAllPaymentsByPMC', [pmc_no])
gst_releases = ReportHelper.execute_sp(cursor, 'GetGSTReleaseDetailsByPMC', [pmc_no])
# ================= DATA MAPPING =================
hold_data = {}
for h in hold_amounts:
hold_data.setdefault(h['Invoice_Id'], {})[h['hold_type_id']] = h['hold_amount']
payments_map = {}
for pay in all_payments:
if pay['invoice_no']:
payments_map.setdefault(pay['invoice_no'], []).append(pay)
# ================= LOG =================
LogHelper.log_action(
"Download PMC Report",
f"User {current_user.id} Download PMC Report '{pmc_no}'"
)
# ================= EXCEL =================
workbook = openpyxl.Workbook()
sheet = workbook.active
sheet.title = "PMC Report"
# HEADER INFO
sheet.append(["", "", "Laxmi Civil Engineering Services PVT. LTD."])
sheet.append(["Contractor Name", contractor_info["Contractor_Name"]])
sheet.append(["State", contractor_info["State_Name"]])
sheet.append(["District", contractor_info["District_Name"]])
sheet.append(["Block", contractor_info["Block_Name"]])
sheet.append([])
base_headers = [
"PMC No","Village","Work Type","Invoice Details","Invoice Date","Invoice No",
"Basic Amount","Debit","After Debit Amount","GST","Amount","TDS",
"SD","On Commission","Hydro Testing","GST SD Amount"
]
hold_headers = [ht['hold_type'] for ht in hold_types]
payment_headers = [
"Final Amount","Payment Amount","TDS Payment","Total Paid","UTR"
]
headers = base_headers + hold_headers + payment_headers
sheet.append(headers)
# STYLE
for cell in sheet[sheet.max_row]:
cell.font = Font(bold=True)
# DATA
seen_invoices = set()
for inv in invoices:
invoice_no = inv["Invoice_No"]
payments = payments_map.get(invoice_no, [])
if invoice_no in seen_invoices:
continue
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"]
]
# HOLD DATA
invoice_holds = hold_data.get(inv["Invoice_Id"], {})
for ht_id in hold_type_map.keys():
row.append(invoice_holds.get(ht_id, ""))
# PAYMENT DATA
row += [
inv["Final_Amount"],
first_payment["Payment_Amount"] if first_payment else "",
first_payment["TDS_Payment_Amount"] if first_payment else "",
first_payment["Total_amount"] if first_payment else "",
first_payment["UTR"] if first_payment else ""
]
sheet.append(row)
# AUTO WIDTH
for col in sheet.columns:
max_len = max((len(str(cell.value)) for cell in col if cell.value), default=0)
sheet.column_dimensions[col[0].column_letter].width = max_len + 2
# SAVE
workbook.save(output_file)
workbook.close()
return output_folder, filename
except Exception as e:
print(f"Error generating PMC report: {e}")
return None
finally:
cursor.close()
connection.close()
# @staticmethod
# def download_pmc_report(pmc_no):
# connection = config.get_db_connection()
# if not connection:
# return None
# 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:
# filename = f"PMC_Report_{pmc_no}.xlsx"
# cursor.callproc('GetContractorDetailsByPMC', [pmc_no])
# contractor_info = next(cursor.stored_results()).fetchone()
# output_folder = FolderAndFile.get_download_folder()
# output_file = FolderAndFile.get_download_path(filename)
# contractor_info = GeneralUse.execute_sp(cursor, 'GetContractorInfoByPmcNo', [pmc_no])
# contractor_info = contractor_info[0] if contractor_info else None
# print("contractor_info:::",contractor_info)
# if not contractor_info:
# return None
# cursor.callproc('GetHoldTypesByContractor', [contractor_info["Contractor_Id"]])
# hold_types = next(cursor.stored_results()).fetchall()
# hold_types = GeneralUse.execute_sp(cursor, 'GetHoldTypesByContractor',[contractor_info["Contractor_Id"]])
# 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()
# invoices = GeneralUse.execute_sp(cursor, 'GetInvoicesByContractorOrPMCNo', [None,pmc_no])
# credit_notes = GeneralUse.execute_sp(cursor, 'NewGetCreditNotesByPMCNo', [pmc_no])
# credit_note_map = {}
# for cn in credit_notes:
# key = (cn["PMC_No"], cn["Invoice_No"])
# key = (str(cn['PMC_No']).strip())
# credit_note_map.setdefault(key, []).append(cn)
# cursor.callproc('GetHoldAmountsByContractor', [contractor_info["Contractor_Id"]])
# hold_amounts = next(cursor.stored_results()).fetchall()
# hold_amounts = GeneralUse.execute_sp(cursor, 'GetHoldAmountsByContractor', [contractor_info["Contractor_Id"]])
# gst_releases = GeneralUse.execute_sp(cursor, 'GetGSTReleaseDetailsByPMC', [pmc_no])
# gst_release_map = {}
# for gr in gst_releases:
# key = (str(gr['PMC_No']).strip())
# gst_release_map.setdefault(key, []).append(gr)
# # ================= DATA MAPPING =================
# 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()
# # ================= LOG =================
# LogHelper.log_action("Download PMC Report",f"User {current_user.id} Download PMC Report '{pmc_no}'")
# ReportHelper.generate_excel(
# 0, contractor_info, invoices, hold_types, hold_data,
# credit_note_map,gst_release_map, output_file)
# return output_folder, filename
# finally:
# cursor.close()
# connection.close()
# connection.close()

View File

@@ -2,9 +2,10 @@ import config
from datetime import datetime
from flask import send_file
import openpyxl
from openpyxl.styles import Font
from openpyxl.styles import Font, PatternFill
from model.FolderAndFile import FolderAndFile
from services.Generalservice import GeneralUse
class ReportHelper:
isSuccess = False
@@ -16,30 +17,6 @@ class ReportHelper:
self.resultMessage = ""
self.data = []
@staticmethod
def execute_sp(cursor, proc_name, params=[], fetch_one=False):
cursor.callproc(proc_name, params)
return (
ReportHelper.fetch_one_result(cursor)
if fetch_one else
ReportHelper.fetch_all_results(cursor)
)
@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):
@@ -59,10 +36,7 @@ class ReportHelper:
cursor = connection.cursor(dictionary=True)
try:
data = ReportHelper.execute_sp(
cursor,
"search_contractor_info",
[
data = GeneralUse.execute_sp(cursor,"search_contractor_info",[
subcontractor_name or None,
pmc_no or None,
state or None,
@@ -71,8 +45,7 @@ class ReportHelper:
village or None,
year_from or None,
year_to or None
]
)
])
except Exception as e:
print(f"Error in search_contractor: {e}")
@@ -84,192 +57,156 @@ class ReportHelper:
return data
@staticmethod
def get_contractor_report(contractor_id):
connection = config.get_db_connection()
cursor = connection.cursor(dictionary=True, buffered=True)
try:
# Contractor Info (only one fetch)
contInfo = ReportHelper.execute_sp(cursor, 'GetContractorInfo', [contractor_id], True)
# Hold Types
hold_types = ReportHelper.execute_sp(cursor, 'GetContractorHoldTypes', [contractor_id])
# Invoices
invoices = ReportHelper.execute_sp(cursor, 'GetContractorInvoices', [contractor_id])
# GST Release
gst_rel = ReportHelper.execute_sp(cursor, 'GetGSTRelease', [contractor_id])
# Hold Release
hold_release = ReportHelper.execute_sp(cursor, 'GetHoldRelease', [contractor_id])
# Credit Note
credit_note = ReportHelper.execute_sp(cursor, 'GetCreditNote', [contractor_id])
# Payments
payments = ReportHelper.execute_sp(cursor, 'GetPayments', [contractor_id])
# Totals
total = {
"sum_invo_basic_amt": float(sum(row['Basic_Amount'] or 0 for row in invoices)),
"sum_invo_debit_amt": float(sum(row['Debit_Amount'] or 0 for row in invoices)),
"sum_invo_after_debit_amt": float(sum(row['After_Debit_Amount'] or 0 for row in invoices)),
"sum_invo_amt": float(sum(row['Amount'] or 0 for row in invoices)),
"sum_invo_gst_amt": float(sum(row['GST_Amount'] or 0 for row in invoices)),
"sum_invo_tds_amt": float(sum(row['TDS_Amount'] or 0 for row in invoices)),
"sum_invo_ds_amt": float(sum(row['SD_Amount'] or 0 for row in invoices)),
"sum_invo_on_commission": float(sum(row['On_Commission'] or 0 for row in invoices)),
"sum_invo_hydro_test": float(sum(row['Hydro_Testing'] or 0 for row in invoices)),
"sum_invo_gst_sd_amt": float(sum(row['GST_SD_Amount'] or 0 for row in invoices)),
"sum_invo_final_amt": float(sum(row['Final_Amount'] or 0 for row in invoices)),
"sum_invo_hold_amt": float(sum(row['hold_amount'] or 0 for row in invoices)),
"sum_gst_basic_amt": float(sum(row['basic_amount'] or 0 for row in gst_rel)),
"sum_gst_final_amt": float(sum(row['final_amount'] or 0 for row in gst_rel)),
"sum_pay_payment_amt": float(sum(row['Payment_Amount'] or 0 for row in payments)),
"sum_pay_tds_payment_amt": float(sum(row['TDS_Payment_Amount'] or 0 for row in payments)),
"sum_pay_total_amt": float(sum(row['Total_amount'] or 0 for row in payments))
}
current_date = datetime.now().strftime('%Y-%m-%d')
finally:
cursor.close()
connection.close()
return {
"contInfo": contInfo,
"invoices": invoices,
"hold_types": hold_types,
"gst_rel": gst_rel,
"payments": payments,
"credit_note": credit_note,
"hold_release": hold_release,
"total": total,
"current_date": current_date
}
@staticmethod
def download_report(contractor_id):
try:
connection = config.get_db_connection()
cursor = connection.cursor(dictionary=True)
def get_contractor_info(contractor_id):
from model.ContractorInfo import ContractorInfo
contractor = ContractorInfo(contractor_id)
return contractor.contInfo if contractor.contInfo else None
# -------- Contractor Info --------
contInfo = ReportHelper.execute_sp(cursor, 'GetContractorInfo', [contractor_id], True)
if not contInfo:
return "No contractor found", 404
# call this method for excel formate written
@staticmethod
def generate_excel(contractor_id, contInfo, invoices, hold_types, hold_data,
credit_note_map, gst_release_map, output_file):
workbook = openpyxl.Workbook()
sheet = workbook.active
sheet.title = "Contractor Report"
# -------- Invoice Data --------
cursor.callproc('FetchInvoicesByContractor', [contractor_id])
# Contractor Info
for field, value in contInfo.items():
sheet.append([field.replace("_", " "), value])
sheet.append([])
invoices = []
for result in cursor.stored_results():
invoices.extend(result.fetchall())
# Headers
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"]
if not invoices:
return "No invoice data found"
hold_headers = [ht['hold_type'] for ht in hold_types]
# -------- Create Workbook --------
workbook = openpyxl.Workbook()
sheet = workbook.active
sheet.title = "Contractor Report"
payment_headers = ["Final Amount", "Payment Amount", "TDS Payment", "Total Paid", "UTR"]
# ================= CONTRACTOR DETAILS =================
sheet.append(["SUB CONTRACTOR DETAILS"])
sheet.cell(row=sheet.max_row, column=1).font = Font(bold=True)
sheet.append([])
all_headers = base_headers + hold_headers + payment_headers
sheet.append(all_headers)
sheet.append(["Name", contInfo.get("Contractor_Name") or ""])
sheet.append(["Mobile No", contInfo.get("Mobile_No") or ""])
sheet.append(["Email", contInfo.get("Email") or ""])
sheet.append(["Village", contInfo.get("Village_Name") or ""])
sheet.append(["Block", contInfo.get("Block_Name") or ""])
sheet.append(["District", contInfo.get("District_Name") or ""])
sheet.append(["State", contInfo.get("State_Name") or ""])
sheet.append(["Address", contInfo.get("Address") or ""])
sheet.append(["GST No", contInfo.get("GST_No") or ""])
sheet.append(["PAN No", contInfo.get("PAN_No") or ""])
sheet.append([])
sheet.append([])
for cell in sheet[sheet.max_row]:
cell.font = Font(bold=True)
cell.fill = PatternFill(start_color="ADD8E6", end_color="ADD8E6", fill_type="solid")
# ================= 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"
processed_gst_releases = set()
appended_credit_keys = set()
previous_pmc_no = None
for inv in invoices:
pmc_no = str(inv["PMC_No"]).strip()
invoice_no = (
inv["invoice_no"].replace(" ", "") if inv["invoice_no"] else ""
if inv["invoice_no"] not in (None, "", 0)
else ""
)
key = (pmc_no)
# Yellow separator
if previous_pmc_no and pmc_no != previous_pmc_no:
sheet.append([""] * len(all_headers))
yellow_fill = PatternFill(start_color="FFFF99", end_color="FFFF99", fill_type="solid")
for cell in sheet[sheet.max_row]:
cell.fill = yellow_fill
previous_pmc_no = pmc_no
# Invoice Row
row = [
pmc_no,
inv.get("Village_Name", ""),
inv.get("Work_Type", ""),
inv.get("Invoice_Details", ""),
inv.get("Invoice_Date", ""),
# inv.get("invoice_no",""),
invoice_no,
inv.get("Basic_Amount", ""),
inv.get("Debit_Amount", ""),
inv.get("After_Debit_Amount", ""),
inv.get("GST_Amount", ""),
inv.get("Amount", ""),
inv.get("TDS_Amount", ""),
inv.get("SD_Amount", ""),
inv.get("On_Commission", ""),
inv.get("Hydro_Testing", ""),
inv.get("GST_SD_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 =================
total_final = 0
total_payment = 0
total_amount = 0
# Hold values
invoice_holds = hold_data.get(inv["Invoice_Id"], {})
for ht_id in [ht['hold_type_id'] for ht in hold_types]:
row.append(invoice_holds.get(ht_id, ""))
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")
]
# Payment values
row += [
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)
sheet.append(row)
# GST Releases
if key in gst_release_map and key not in processed_gst_releases:
for gr in gst_release_map[key]:
gst_row = [
pmc_no, "", "", "GST Release Note", "", gr.get("Invoice_No", ""),
gr.get("Basic_Amount", ""), "", "", "", "", "", "", "", "", ""
]
# ================= TOTAL ROW =================
sheet.append([])
sheet.append([
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"TOTAL",
total_final,
total_payment,
"",
total_amount,
""
])
gst_row += [""] * len(hold_headers)
# ================= 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
gst_row += [
gr.get("Final_Amount", ""),
"",
"",
gr.get("Total_Amount", ""),
gr.get("UTR", "")
]
sheet.append(gst_row)
processed_gst_releases.add(key)
# Credit Notes
if key in credit_note_map and key not in appended_credit_keys:
for cn in credit_note_map[key]:
cn_row = [
pmc_no, "", "", cn.get("Invoice_Details", "Credit Note"), "",
cn.get("Invoice_No", ""),
cn.get("Basic_Amount", ""),
cn.get("Debit_Amount", ""),
cn.get("After_Debit_Amount", ""),
cn.get("GST_Amount", ""),
cn.get("Amount", ""),
"", "", "", "", ""
]
cn_row += [""] * len(hold_headers)
cn_row += [
cn.get("Final_Amount", ""),
"",
"",
cn.get("Total_Amount", ""),
cn.get("UTR", "")
]
sheet.append(cn_row)
appended_credit_keys.add(key)
# SAVE ONCE AT END
workbook.save(output_file)
# ================= 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)

View File

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

View File

@@ -1,7 +1,6 @@
from model.Utilities import ItemCRUDType
from model.ItemCRUD import ItemCRUD
class Subcontractor:
def __init__(self):
self.isSuccess = False

View File

@@ -8,10 +8,12 @@ class ItemCRUDType(Enum):
State = 4
HoldType = 5
Subcontractor = 6
GSTRelease = 7
Invoice = 8
class RegEx:
patternAlphabetOnly = "^[A-Za-z ]+$"
patternAlphabetOnly = r"^[A-Za-z ]+$"
allPattern = r"^(?!\s*$).+"
class ResponseHandler:
@@ -62,5 +64,5 @@ class HtmlHelper:
@staticmethod
def json_response(message_obj, status_code):
return jsonify(message_obj), status_code
#May need to refactor further

View File

@@ -1,10 +1,11 @@
# return blocks
from model.Utilities import ResponseHandler, HtmlHelper, ItemCRUDType
import config
import mysql.connector
from model.ItemCRUD import ItemCRUD
class Village:
isSuccess = False
resultMessage = ""
@@ -12,12 +13,19 @@ class Village:
def __init__(self):
self.isSuccess = False
self.resultMessage = ""
self.response = {}
self.village = ItemCRUD(itemType=ItemCRUDType.Village)
# 🔹 Helper: sync status
def _set_status(self, village):
self.isSuccess = village.isSuccess
self.resultMessage = village.resultMessage
# UPDATED (safe handling)
if hasattr(village, "response"):
self.response = village.response
self.resultMessage = village.response.get("message", "")
else:
self.resultMessage = village.resultMessage
# 🔹 Helper: get request data
def _get_form_data(self, request):
@@ -29,8 +37,9 @@ class Village:
block_id, village_name = self._get_form_data(request)
if not village_name:
self.response = ResponseHandler.invalid_name("village")
self.resultMessage = self.response["message"]
self.isSuccess = False
self.resultMessage = "Village name cannot be empty"
return
try:
@@ -66,8 +75,9 @@ class Village:
block_id, village_name = self._get_form_data(request)
if not village_name:
self.response = ResponseHandler.invalid_name("village")
self.resultMessage = self.response["message"]
self.isSuccess = False
self.resultMessage = "Village name cannot be empty"
return None
try:
@@ -103,8 +113,9 @@ class Village:
block_id, village_name = self._get_form_data(request)
if not village_name:
self.response = ResponseHandler.invalid_name("village")
self.resultMessage = self.response["message"]
self.isSuccess = False
self.resultMessage = "Village name cannot be empty"
return
try:
@@ -164,9 +175,11 @@ class Village:
except mysql.connector.Error as e:
print(f"Error fetching blocks: {e}")
self.isSuccess = False
self.resultMessage = HtmlHelper.json_response(
ResponseHandler.fetch_failure("block"), 500
)
# FIXED (removed jsonify response)
self.response = ResponseHandler.fetch_failure("block")
self.resultMessage = self.response["message"]
return []
finally:

View File

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

View File

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

View File

@@ -0,0 +1,30 @@
class GeneralUse:
data=[]
@staticmethod
def execute_sp(cursor, proc_name, params=[], fetch_one=False):
cursor.callproc(proc_name, params)
return (
GeneralUse.fetch_one_result(cursor)
if fetch_one else
GeneralUse.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

Some files were not shown because too many files have changed in this diff Show More