Initial commit

This commit is contained in:
2025-06-19 23:04:49 +05:30
commit 45388d0b5e
548 changed files with 13730 additions and 0 deletions

8
.gitignore vendored Normal file
View File

@@ -0,0 +1,8 @@
venv/
*.pyc
__pycache__/
.env
.uploads
static/download/

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

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

1
.idea/.name generated Normal file
View File

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

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

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

View File

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

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

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

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

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

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

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

18
Dockerfile Normal file
View File

@@ -0,0 +1,18 @@
# Use official Python image
FROM python:3.9
# Set working directory inside container
WORKDIR /app
# Copy all files to container
COPY . .
# Install dependencies
RUN pip install --no-cache-dir -r requirements.txt
# Expose Flask's default port
EXPOSE 5000
# Run Flask app
CMD ["python", "main.py"]

1
README.md Normal file
View File

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

114
app.log Normal file
View File

@@ -0,0 +1,114 @@
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

18
config.py Normal file
View File

@@ -0,0 +1,18 @@
import mysql.connector
import os
# Get MySQL credentials from environment variables
MYSQL_HOST = os.getenv("MYSQL_HOST", "127.0.0.1")
MYSQL_USER = os.getenv("MYSQL_USER", "root")
MYSQL_PASSWORD = os.getenv("MYSQL_PASSWORD", "admin")
MYSQL_DB = os.getenv("MYSQL_DB", "test")
# Connect to MySQL
def get_db_connection():
return mysql.connector.connect(
host=MYSQL_HOST,
user=MYSQL_USER,
password=MYSQL_PASSWORD,
database=MYSQL_DB
)

35
docker-compose.yml Normal file
View File

@@ -0,0 +1,35 @@
version: "3.8"
services:
flask-app:
build: .
ports:
- "5000:5000"
depends_on:
- mysql
environment:
- MYSQL_HOST=mysql
- MYSQL_USER=root
- MYSQL_PASSWORD=root
- MYSQL_DB=test
networks:
- mynetwork
mysql:
image: mysql:8.0
restart: always
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: test
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
networks:
- mynetwork
volumes:
mysql-data:
networks:
mynetwork:

7453
main.py Normal file

File diff suppressed because it is too large Load Diff

4
requirements.txt Normal file
View File

@@ -0,0 +1,4 @@
Flask
mysql-connector-python
openpyxl
pandas

89
static/css/base.css Normal file
View File

@@ -0,0 +1,89 @@
body {
margin: 0;
font-family: Arial, sans-serif;
background-color: #f5f5f5;
display: flex;
}
/* Sidebar */
.sidebar {
width: 250px;
height: 100vh;
background-color: #ffffff;
position: fixed;
left: -250px;
transition: left 0.3s ease;
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
padding-top: 20px;
}
.sidebar.open {
left: 0;
}
/* Sidebar Navigation */
.nav-menu {
list-style: none;
padding: 0;
margin: 0;
}
.nav-item {
width: 100%;
}
.nav-link {
display: flex;
align-items: center;
text-decoration: none;
color: #333;
padding: 15px 20px;
font-size: 16px;
transition: background-color 0.3s, color 0.3s;
}
.nav-link i {
margin-right: 10px;
font-size: 18px;
}
.nav-link:hover, .nav-link.active {
background-color: #e6f7ff;
color: #007bff;
}
/* Menu Button */
.menu-icon {
position: absolute;
top: 15px;
left: 15px;
font-size: 24px;
cursor: pointer;
background: none;
border: none;
}
/* Content Area */
.content {
margin-left: 0;
padding: 20px;
width: 100%;
transition: margin-left 0.3s ease;
}
.content.shift {
margin-left: 250px;
}
@media (max-width: 768px) {
.sidebar {
width: 200px;
left: -200px;
}
.sidebar.open {
left: 0;
}
.content.shift {
margin-left: 200px;
}
}

226
static/css/index.css Normal file
View File

@@ -0,0 +1,226 @@
body {
margin: 0;
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
background-color: #f5f5f5;
}
/* Sidebar */
.sidebar {
width: 250px;
height: 100%;
background-color: #ffffff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
align-items: center;
padding-top: 20px;
position: fixed;
}
.logo {
width: 80px;
margin-bottom: 20px;
}
.nav-menu {
width: 100%;
list-style: none;
padding: 0;
margin: 0;
}
.nav-item {
width: 100%;
}
.nav-link {
display: flex;
align-items: center;
text-decoration: none;
color: #333;
padding: 15px 20px;
font-size: 16px;
transition: background-color 0.3s, color 0.3s;
}
.nav-link:hover,
.nav-link.active {
background-color: #e6f7ff;
color: #007bff;
}
.nav-link i {
margin-right: 10px;
font-size: 18px;
}
.user-section {
margin-top: auto;
width: 100%;
padding: 20px;
display: flex;
align-items: center;
border-top: 1px solid #eee;
}
.user-section img {
width: 50px;
height: 50px;
border-radius: 50%;
margin-right: 10px;
}
.user-info {
display: flex;
flex-direction: column;
}
.user-info span {
font-size: 14px;
color: #333;
}
/* Main content area */
.content {
margin-left: 250px;
padding: 20px;
width: calc(100% - 250px);
}
/* Menu Cards */
.menu {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.card {
background-color: #fff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
border-radius: 8px;
padding: 20px;
text-align: center;
flex: 1 1 calc(30% - 20px);
max-width: calc(30% - 20px);
}
.card h2 {
margin: 0 0 10px;
font-size: 20px;
}
.btn {
display: inline-block;
padding: 10px 20px;
color: #fff;
background-color: #007bff;
border-radius: 4px;
text-decoration: none;
font-size: 14px;
transition: background-color 0.3s;
}
.btn:hover {
background-color: #0056b3;
}
/* Company Info */
.company-info {
text-align: center;
padding: 20px;
background-color: Whitesmoke;
color: blue;
margin-left: 250px;
}
.company-name {
font-size: 30px;
font-weight: bold;
margin: 0;
}
.app-name {
font-weight: bold;
app-name-shadow:0 2px 4px rgba(0, 0, 0, 0.1);
font-size: 24px;
margin: 5px 0 0;
}
/* Responsive Design */
@media screen and (max-width: 768px) {
.sidebar {
width: 100%;
height: auto;
position: static;
}
.content {
margin-left: 0;
width: 100%;
}
.menu {
flex-direction: column;
align-items: center;
}
.card {
flex: 1 1 100%;
max-width: 100%;
min-width: 50%;
}
}
@media screen and (max-width: 480px) {
.nav-link {
font-size: 14px;
padding: 10px 15px;
}
.btn {
font-size: 12px;
padding: 8px 15px;
}
}
@media screen and (max-width: 768px) {
.sidebar {
width: 100%;
height: auto;
position: static;
}
.content {
margin-left: 0;
width: 100%;
}
.menu {
flex-direction: column;
align-items: center;
}
.card {
flex: 1 1 100%;
max-width: 100%;
min-width: 50%;
}
.company-info {
margin-left: 0;
}
}
@media screen and (max-width: 480px) {
.nav-link {
font-size: 14px;
padding: 10px 15px;
}
.btn {
font-size: 12px;
padding: 8px 15px;
}
.user-section {
flex-direction: column;
align-items: flex-start;
gap: 10px;
}
.user-section img {
margin-right: 0;
}
.card {
min-width: 90%;
}
}

395
static/css/invoice.css Normal file
View File

@@ -0,0 +1,395 @@
/* General Styles */
h2 {
text-align: center;
font-size: 24px;
color: #333;
margin-bottom: 20px;
}
/* Form Styling */
form {
width:50%;
background: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
gap: 15px;
}
/* Responsive Form Layout */
.row1,
.row2,
.row3 {
display: grid;
gap: 15px;
}
.row2,
.row3 {
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
label {
font-weight: bold;
display: block;
margin-bottom: 6px;
}
input,
textarea,
select {
width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 6px;
font-size: 16px;
box-sizing: border-box;
}
/* Button Styling */
.button {
padding: 12px;
background-color: #007bff;
color: white;
border: none;
border-radius: 6px;
font-size: 18px;
cursor: pointer;
transition: background-color 0.3s ease-in-out;
}
.button:hover {
background-color: #0056b3;
}
/* Dynamic Hold Amount Fields */
.hold-row {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.hold-amount-field {
display: flex;
align-items: center;
gap: 10px;
padding: 10px;
background-color: #f9f9f9;
border: 1px solid #ddd;
border-radius: 4px;
flex-wrap: wrap;
}
.hold-amount-field select,
.hold-amount-field input {
flex: 1;
min-width: 100px;
}
.hold-amount-field button {
background-color: red;
color: white;
font-size: 14px;
padding: 8px 10px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.hold-amount-field button:hover {
background-color: #c0392b;
}
/* Success Alert Box */
.success-alert {
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
background-color: #4CAF50;
color: #fff;
padding: 15px 25px;
border-radius: 5px;
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
opacity: 0;
visibility: hidden;
transition: opacity 0.5s ease, visibility 0.5s ease;
z-index: 1000;
}
.success-alert.show {
opacity: 1;
visibility: visible;
}
/* Table Styles */
.invoice-table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
overflow-x: auto;
}
.invoice-table th,
.invoice-table td {
border: 1px solid #ddd;
padding: 10px;
text-align: left;
font-size: 14px;
word-break: break-word;
}
.invoice-table th {
background-color: #007bff;
color: #fff;
}
.invoice-table tr:nth-child(even) {
background-color: #f9f9f9;
}
.invoice-table tr:hover {
background-color: #f1f1f1;
}
/* icon */
.icon {
width: 20px;
height: 20px;
cursor: pointer;
transition: transform 0.2s ease-in-out, opacity 0.2s ease-in-out;
}
.icon:hover {
transform: scale(1.5);
opacity: 0.8;
}
.edit-icon:hover {
filter: drop-shadow(0 0 5px #007bff); /* Blue glow for edit */
}
.delete-icon:hover {
filter: drop-shadow(0 0 5px #ff0000); /* Red glow for delete */
}
/* Center the buttons and apply consistent styling */
.button-container {
display: flex;
justify-content: center; /* Center buttons horizontally */
gap: 10px; /* Space between buttons */
margin-top: 20px; /* Add some top margin */
}
.action-button {
background-color: #007BFF; /* Blue background */
color: white; /* White text */
padding: 15px 30px; /* Larger padding for bigger buttons */
border: none; /* Remove border */
border-radius: 5px; /* Rounded corners */
cursor: pointer; /* Pointer cursor on hover */
font-size: 18px; /* Larger font size */
text-align: center; /* Center text */
text-decoration: none; /* Remove underline */
transition: background-color 0.3s ease; /* Smooth hover transition */
}
.action-button:hover {
background-color: #0056b3; /* Darker blue on hover */
}
#addStateForm, #stateTable {
display: none; /* Initially hide both the form and the table */
}
/* Success Popup */
.success-popup {
display: none;
color: green;
font-size: 1.2em;
margin-top: 10px;
}
/* Sorting buttons */
.sortable .sort-buttons {
margin-left: 5px;
}
.sortable {
cursor: pointer;
user-select: none;
}
.sort-buttons a {
text-decoration: none;
color: black;
font-weight: bold;
margin-left: 5px;
margin-right: 5px;
}
.sort-buttons a:hover {
text-decoration: underline;
}
.back-button {
display: inline-block;
margin-top: 20px;
padding: 8px 15px;
background-color: #28a745;
color: white;
border-radius: 5px;
text-decoration: none;
font-size: 16px;
}
.back-button:hover {
background-color: #218838;
}
span .sort-desc:hover{
cursor: pointer;
}
span .sort-asc:hover{
cursor: pointer;
}
/* Responsive Design */
@media (max-width: 1024px) {
form {
padding: 15px;
}
.row2,
.row3 {
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.invoice-table th,
.invoice-table td {
font-size: 12px;
padding: 8px;
}
}
@media (max-width: 768px) {
.row1,
.row2,
.row3 {
grid-template-columns: 1fr;
}
.hold-amount-field {
flex-direction: column;
gap: 5px;
align-items: flex-start;
}
.hold-amount-field select,
.hold-amount-field input {
width: 100%;
}
.invoice-table {
display: block;
overflow-x: auto;
white-space: nowrap;
}
}
@media (max-width: 480px) {
body {
max-width: 100%;
padding: 10px;
}
form {
padding: 10px;
}
.invoice-table th,
.invoice-table td {
font-size: 12px;
padding: 5px;
}
button {
font-size: 16px;
padding: 10px;
}
}
/* Additional Media Queries */
/* For tablets and medium devices */
@media (max-width: 992px) {
form {
width: 90%;
}
.button-container {
flex-direction: column;
align-items: center;
}
.action-button {
width: 100%;
max-width: 300px;
}
}
/* For smaller tablets and large phones */
@media (max-width: 600px) {
.button-container {
flex-direction: column;
align-items: stretch;
}
.action-button {
width: 100%;
}
.icon {
width: 16px;
height: 16px;
}
.success-alert {
width: 90%;
font-size: 14px;
padding: 10px 15px;
}
}
/* For very small phones */
@media (max-width: 360px) {
h2 {
font-size: 20px;
}
.back-button {
width: 100%;
text-align: center;
font-size: 14px;
padding: 8px 10px;
}
.sort-buttons a {
font-size: 12px;
}
.invoice-table th,
.invoice-table td {
font-size: 10px;
padding: 4px;
}
}

313
static/css/invoice1.css Normal file
View File

@@ -0,0 +1,313 @@
/* General Styling */
body {
font-family: Arial, sans-serif;
margin: 20px;
background-color: #f9f9f9;
color: #333;
}
/* Header Styling */
h1, h2, h3 {
color: #0056b3;
text-align: center;
}
/* Table Styling */
table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
table th, table td {
border: 1px solid #ddd;
padding: 8px;
text-align: center;
}
table th {
background-color: #007bff;
color: white;
font-weight: bold;
cursor: pointer;
position: relative;
}
table tr:nth-child(even) {
background-color: #f2f2f2;
}
table tr:hover {
background-color: #ddd;
}
/* Sort Dropdown */
.sort-options {
display: none;
position: absolute;
background: white;
border: 1px solid black;
padding: 5px;
z-index: 100;
width: 120px;
text-align: center;
}
.sort-options button {
display: block;
width: 100%;
border: none;
background: none;
padding: 5px;
cursor: pointer;
}
.sort-options button:hover {
background-color: #f0f0f0;
}
/* Form Styling */
form {
max-width: 700px;
margin: 0 auto;
padding: 20px;
background: #fff;
border: 1px solid #ddd;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
form label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
form input[type="text"],
form input[type="number"],
form input[type="date"],
form input[type="email"],
form textarea,
select {
width: 100%;
padding: 10px;
margin-bottom: 15px;
border: 1px solid #ddd;
border-radius: 5px;
box-sizing: border-box;
}
form textarea {
resize: vertical;
}
/* Button Styling */
.button, form button {
width: 100%;
padding: 10px;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
text-align: center;
}
.button:hover, form button:hover {
background-color: #0056b3;
}
/* Back Button */
.back-button {
background-color: red;
color: white;
padding: 10px 20px;
text-decoration: none;
font-weight: bold;
border-radius: 5px;
display: inline-block;
margin-top: 20px;
text-align: center;
}
.back-button:hover {
background-color: darkred;
}
/* Success Alert */
.success-alert {
display: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #d4edda;
color: #155724;
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
text-align: center;
font-size: 18px;
font-weight: bold;
}
.success-popup i {
color: green;
font-size: 30px;
margin-right: 10px;
}
/* Error Message */
.error-message {
color: red;
font-size: 14px;
margin-top: 5px;
}
/* Table Icons */
td img {
width: 20px; /* Adjust as needed */
height: 20px; /* Adjust as needed */
transition: transform 0.3s ease; /* Smooth transition for hover effect */
}
td img:hover {
transform: scale(1.2); /* Slight zoom effect on hover */
}
/* Select Dropdown */
select {
width: 100%;
padding: 12px 15px;
margin: 10px 0;
border: 1px solid #ccc;
border-radius: 5px;
font-size: 14px;
background-color: #fff;
box-sizing: border-box;
appearance: none;
}
/* Custom Dropdown Arrow */
select::-ms-expand {
display: none;
}
select:focus {
outline: none;
border-color: #4CAF50;
}
select option {
padding: 12px 15px;
font-size: 14px;
}
option[disabled] {
color: #aaa;
font-style: italic;
}
/* Save Button */
.save-button {
background-color: green;
color: white;
padding: 15px;
text-decoration: none;
font-weight: bold;
border-radius: 5px;
display: flex;
justify-content: center;
align-items: center;
margin: 20px auto;
text-align: center;
}
.save-button:hover {
background-color: darkgreen;
}
/* Responsive Design */
@media (max-width: 768px) {
form {
max-width: 100%;
padding: 15px;
}
table th, table td {
padding: 6px;
font-size: 14px;
}
.button, form button {
font-size: 14px;
padding: 8px;
}
}
/* Additional Media Queries */
/* For tablets and medium-sized screens */
@media (max-width: 992px) {
form {
padding: 18px;
}
table th, table td {
font-size: 14px;
padding: 6px;
}
.save-button, .back-button, .button, form button {
font-size: 15px;
}
}
/* For smaller tablets and large phones */
@media (max-width: 600px) {
body {
margin: 10px;
}
h1, h2, h3 {
font-size: 20px;
}
table th, table td {
font-size: 13px;
padding: 5px;
}
.success-alert {
width: 90%;
font-size: 16px;
padding: 15px;
}
.button, form button, .save-button, .back-button {
padding: 10px;
font-size: 14px;
}
}
/* For very small phones */
@media (max-width: 360px) {
h1, h2, h3 {
font-size: 18px;
}
.save-button, .back-button {
width: 100%;
font-size: 13px;
padding: 10px;
}
table th, table td {
font-size: 12px;
padding: 4px;
}
form input, form select, form textarea {
font-size: 14px;
}
}

181
static/css/report.css Normal file
View File

@@ -0,0 +1,181 @@
h2 {
text-align: center;
font-size: 24px;
color: #333;
margin-bottom: 20px;
}
/* Form Styling */
.info {
width: 60%;
background: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
gap: 15px;
}
/* Responsive Form Layout */
.row1,
.row2,
.row3 {
display: grid;
gap: 15px;
}
.row2,
.row3 {
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
label {
font-weight: bold;
display: block;
margin-bottom: 6px;
}
input,
textarea,
select {
width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 6px;
font-size: 16px;
box-sizing: border-box;
}
/* Table styling */
.table-wrapper {
overflow-x: auto;
}
table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
table th, table td {
border: 1px solid #ddd;
padding: 8px;
text-align: center;
}
table th {
background-color: #007bff;
color: white;
font-weight: bold;
}
table tr:nth-child(even) {
background-color: #f2f2f2;
}
table tr:hover {
background-color: #ddd;
}
.download-btn {
display: inline-block;
padding: 10px 15px;
background-color: #28a745;
color: white;
text-decoration: none;
border-radius: 5px;
margin-top: 15px;
}
.total-table {
width: 35%;
}
/* Responsive Design */
@media (max-width: 1024px) {
.info {
padding: 15px;
}
.row2,
.row3 {
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.invoice-table th,
.invoice-table td {
font-size: 12px;
padding: 8px;
}
}
@media (max-width: 768px) {
.row1,
.row2,
.row3 {
grid-template-columns: 1fr;
}
}
@media (max-width: 480px) {
body {
max-width: 100%;
padding: 10px;
}
.info {
padding: 10px;
}
table th,
table td {
font-size: 10px;
padding: 6px;
}
}
/* Ensure table responsiveness */
@media (max-width: 600px) {
.table-wrapper {
overflow-x: auto;
}
table {
min-width: 600px;
}
}
/* Extra Small Devices (max-width: 360px) */
@media (max-width: 360px) {
h2 {
font-size: 20px;
margin-bottom: 15px;
}
.info {
width: 100%;
padding: 8px;
}
input,
textarea,
select {
font-size: 14px;
padding: 8px;
}
.download-btn {
font-size: 14px;
padding: 8px 12px;
}
table th,
table td {
font-size: 9px;
padding: 5px;
}
.total-table {
width: 100%;
}
}

212
static/css/show_excel.css Normal file
View File

@@ -0,0 +1,212 @@
/* General Styles */
body {
font-family: Arial, sans-serif;
margin: 20px;
padding: 20px;
background-color: #f4f4f9;
color: #333;
}
/* Headings */
h1, h2 {
color: #2c3e50;
}
/* File Information Section */
ul {
list-style-type: none;
padding: 0;
}
ul li {
background: #ecf0f1;
margin: 5px 0;
padding: 10px;
border-radius: 5px;
}
/* Error Messages */
.errors {
background-color: #ffdddd;
border: 1px solid #ff4d4d;
padding: 15px;
margin-bottom: 20px;
border-radius: 5px;
}
.errors h2 {
color: #ff4d4d;
}
.error {
color: #d8000c;
font-weight: bold;
}
/* Table Styles */
.table-container {
max-width: 100%;
overflow-x: auto; /* Allows horizontal scrolling */
margin-bottom: 20px;
border: 1px solid #ddd; /* Optional for better visibility */
}
table {
width: 100%;
border-collapse: collapse;
background-color: white;
table-layout: auto; /* Let the columns adjust based on content */
}
th, td {
padding: 10px;
border: 1px solid #ddd;
text-align: left;
word-wrap: break-word; /* Prevents text from overflowing */
}
th {
background-color: #3498db;
color: white;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
/* Set input width to 100px */
input[type="text"] {
width: 200px; /* Set a fixed width of 100px */
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box; /* Ensures padding is included in width calculation */
white-space: nowrap; /* Prevent line breaks */
overflow: hidden; /* Prevents overflow */
text-overflow: ellipsis; /* Shows ellipsis if the content is too long */
}
/* Buttons */
button {
display: inline-block;
background-color: #27ae60;
color: white;
padding: 10px 15px;
text-decoration: none;
border: none;
cursor: pointer;
border-radius: 5px;
transition: background 0.3s ease;
font-size: 16px;
width: 100%; /* Ensures button is centered */
}
.back-button {
display: inline-block;
background-color: #27ae60;
color: white;
padding: 10px 15px;
text-decoration: none;
border: none;
cursor: pointer;
border-radius: 5px;
transition: background 0.3s ease;
font-size: 16px;
width: 10%; /* Ensures button is centered */
}
/* Hover Effects */
button:hover, .back-button:hover {
background-color: #219150;
}
button:disabled {
background-color: #95a5a6;
cursor: not-allowed;
}
/* Back Button */
.back-button {
background-color: #e74c3c;
}
.back-button:hover {
background-color: #c0392b;
}
/* Center Save Data Button */
form {
display: flex;
flex-direction: column;
align-items: center;
}
.save-button {
margin-top: 20px;
width: 50%;
}
/* Responsive Design */
@media (max-width: 768px) {
.table-container {
display: block;
overflow-x: auto;
white-space: nowrap;
}
table {
width: 100%;
table-layout: auto; /* Let the table adjust to fit its content */
}
input[type="text"] {
width: 100px; /* Fixed width of 100px */
padding: 6px; /* Smaller padding on mobile */
}
button, .back-button {
width: 100%;
text-align: center;
}
}
@media (max-width: 480px) {
body {
margin: 10px;
padding: 10px;
}
h1, h2 {
font-size: 20px;
text-align: center;
}
input[type="text"] {
width: 80px;
font-size: 14px;
}
th, td {
font-size: 12px;
padding: 6px;
}
.save-button {
width: 100%;
}
.back-button {
width: 100%;
font-size: 14px;
}
button {
font-size: 14px;
padding: 8px 12px;
}
.errors {
font-size: 14px;
padding: 10px;
}
}

448
static/css/style.css Normal file
View File

@@ -0,0 +1,448 @@
/* General styling */
body {
font-family: Arial, sans-serif;
margin: 20px;
background-color: #f9f9f9;
color: #333;
}
/* Header styling */
h1 {
color: back;
text-align: center;
}
h2 {
color: #0056b3;
text-align: center;
}
h3 {
color: #0056b3;
}
/* Table styling */
table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
table th, table td {
border: 1px solid #ddd;
padding: 8px;
text-align: center;
}
table th {
background-color: #007bff;
color: white;
font-weight: bold;
}
table tr:nth-child(even) {
background-color: #f2f2f2;
}
table tr:hover {
background-color: #ddd;
}
/* Form styling */
form {
max-width: 600px;
margin: 0 auto;
padding: 20px;
background: #fff;
border: 1px solid #ddd;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
form label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
form input[type="text"], form input[type="number"], form input[type="date"],form input[type="email"], form textarea {
width: 100%;
padding: 10px;
margin-bottom: 15px;
border: 1px solid #ddd;
border-radius: 5px;
box-sizing: border-box;
}
form textarea {
resize: vertical;
}
form button {
width: 100%;
padding: 10px;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
}
form button:hover {
background-color: #0056b3;
}
/* Style the <h1> elements to display inline */
h1 {
display: inline-block;
margin-right: 10px; /* Spacing between buttons */
}
/* Style the <a> tags to look like buttons */
.button {
text-decoration: none; /* Remove underline */
padding: 10px 20px; /* Add padding for size */
background-color: #4CAF50; /* Green background color */
color: white; /* White text */
font-size: 16px; /* Font size */
border-radius: 5px; /* Rounded corners */
border: none; /* Remove default border */
cursor: pointer; /* Cursor style */
transition: background-color 0.3s ease; /* Smooth transition for hover */
}
/* Change background color on hover */
.button:hover {
background-color: #45a049;
}
/* Style for the Back Button */
.back-button {
background-color: red;
color: white;
padding: 10px 20px;
text-decoration: none;
font-weight: bold;
border-radius: 5px;
display: inline-block;
margin-top: 20px;
text-align: center;
}
.back-button:hover {
background-color: darkred;
}
/* Styling for the select dropdown */
select {
width: 100%; /* Use full width for better responsiveness */
padding: 12px 15px; /* Increased padding for better spacing */
margin: 10px 0; /* Spacing above and below */
border: 1px solid #ccc; /* Border color */
border-radius: 5px; /* Rounded corners */
font-size: 14px; /* Font size for text */
background-color: #fff; /* White background */
box-sizing: border-box; /* Ensures padding and border are included in width */
appearance: none; /* Remove default dropdown arrow for custom styling */
}
/* Custom dropdown arrow */
select::-ms-expand {
display: none; /* Remove the default arrow for IE/Edge */
}
select:focus {
outline: none; /* Remove outline when focused */
border-color: #4CAF50; /* Change border color when focused */
}
/* Option styling for the select */
select option {
padding: 12px 15px; /* Padding for each option */
font-size: 14px; /* Font size */
}
/* Style the placeholder (default) option */
option[disabled] {
color: #aaa; /* Light grey color for disabled option */
font-style: italic; /* Italicize the disabled option */
}
/* Label styling */
label {
font-size: 16px;
font-weight: bold;
margin-bottom: 5px;
display: block;
}
.save-button {
background-color: Green;
color: white;
padding: 15px;
text-decoration: none;
font-weight: bold;
border-radius: 5px;
display:flex;
justify-content: center;
align-item: center;
margin: 20px;
text-align: center;
}
.save-button:hover {
background-color: darkGreen;
}
.success-popup {
display: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #d4edda;
color: #155724;
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
text-align: center;
font-size: 18px;
font-weight: bold;
}
.success-popup i {
color: green;
font-size: 30px;
margin-right: 10px;
}
.error-message {
color: red;
font-size: 14px;
margin-top: 5px;
}
.icon {
width: 20px;
height: 20px;
cursor: pointer;
transition: transform 0.2s ease-in-out, opacity 0.2s ease-in-out;
}
.icon:hover {
transform: scale(1.5);
opacity: 0.8;
}
.edit-icon:hover {
filter: drop-shadow(0 0 5px #007bff); /* Blue glow for edit */
}
.delete-icon:hover {
filter: drop-shadow(0 0 5px #ff0000); /* Red glow for delete */
}
/* Search Bar Container */
.search-container {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
/* Search Bar Input */
#searchBar {
padding: 8px;
font-size: 14px;
border: 1px solid #ccc;
border-radius: 5px;
width: 200px;
transition: 0.3s;
}
/* Search Bar Focus Effect */
#searchBar:focus {
border-color: #007bff;
outline: none;
box-shadow: 0 0 5px rgba(0, 123, 255, 0.5);
}
/* Center the buttons and apply consistent styling */
.button-container {
display: flex;
justify-content: center; /* Center buttons horizontally */
gap: 10px; /* Space between buttons */
margin-top: 20px; /* Add some top margin */
}
.action-button {
background-color: #007BFF; /* Blue background */
color: white; /* White text */
padding: 15px 30px; /* Larger padding for bigger buttons */
border: none; /* Remove border */
border-radius: 5px; /* Rounded corners */
cursor: pointer; /* Pointer cursor on hover */
font-size: 18px; /* Larger font size */
text-align: center; /* Center text */
text-decoration: none; /* Remove underline */
transition: background-color 0.3s ease; /* Smooth hover transition */
}
.action-button:hover {
background-color: #0056b3; /* Darker blue on hover */
}
#addStateForm, #stateTable {
display: none; /* Initially hide both the form and the table */
}
/* Success Popup */
.success-popup {
display: none;
color: green;
font-size: 1.2em;
margin-top: 10px;
}
/* Sorting buttons */
.sortable .sort-buttons {
margin-left: 5px;
}
.sortable {
cursor: pointer;
user-select: none;
}
.sort-buttons a {
text-decoration: none;
color: black;
font-weight: bold;
margin-left: 5px;
margin-right: 5px;
}
.sort-buttons a:hover {
text-decoration: underline;
}
.back-button {
display: inline-block;
margin-top: 20px;
padding: 8px 15px;
background-color: #28a745;
color: white;
border-radius: 5px;
text-decoration: none;
font-size: 16px;
}
.back-button:hover {
background-color: #218838;
}
span .sort-desc:hover{
cursor: pointer;
}
span .sort-asc:hover{
cursor: pointer;
}
.sortable select {
background-color: #007BFF; /* Blue background */
color: white; /* White text */
border: none;
border-radius: 4px;
padding: 5px 10px;
font-size: 14px;
cursor: pointer;
appearance: none; /* Remove default browser styling */
background-image: url("data:image/svg+xml;charset=US-ASCII,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-caret-down-fill' viewBox='0 0 16 16'%3E%3Cpath d='M7.247 11.14 2.451 5.658c-.566-.63-.106-1.658.753-1.658h9.592c.86 0 1.32 1.027.753 1.658L8.753 11.14a1 1 0 0 1-1.506 0z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 10px center;
background-size: 12px;
}
.sortable select:focus {
outline: none;
background-color: #0056b3; /* Darker blue on focus */
}
.download-btn {
display: inline-block;
padding: 10px 15px;
background-color: #28a745;
color: white;
text-decoration: none;
border-radius: 5px;
margin-top: 15px;
}
@media (max-width: 480px) {
body {
margin: 10px;
padding: 10px;
}
h1, h2, h3 {
font-size: 18px;
text-align: center;
}
table th, table td {
font-size: 12px;
padding: 6px;
}
form {
padding: 10px;
max-width: 100%;
}
form input[type="text"],
form input[type="number"],
form input[type="date"],
form input[type="email"],
form textarea,
select {
padding: 8px;
font-size: 14px;
}
form button,
.button,
.back-button,
.save-button,
.action-button {
font-size: 14px;
padding: 10px;
width: 100%;
}
.button-container {
flex-direction: column;
gap: 10px;
}
#searchBar {
width: 100%;
font-size: 14px;
}
.sortable select {
font-size: 14px;
padding: 8px 10px;
background-position: right 8px center;
}
}

View File

@@ -0,0 +1,199 @@
/* Global box-sizing for predictable sizing */
*, *::before, *::after {
box-sizing: border-box;
}
h2 {
text-align: center;
/* Fluid font size between 20px and 24px */
font-size: clamp(20px, 3vw, 24px);
color: #333;
margin-bottom: 20px;
}
/* Form Styling */
.info {
width: 60%;
max-width: 900px; /* optional max-width */
background: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
gap: 15px;
margin: 0 auto; /* center horizontally */
}
/* Responsive Form Layout */
.row1,
.row2,
.row3 {
display: grid;
gap: 15px;
}
.row2,
.row3 {
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
label {
font-weight: bold;
display: block;
margin-bottom: 6px;
}
input,
textarea,
select {
width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 6px;
/* Fluid font size between 14px and 16px */
font-size: clamp(14px, 1.5vw, 16px);
}
/* Table styling */
.table-wrapper {
overflow-x: auto;
}
table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
table th,
table td {
border: 1px solid #ddd;
padding: 8px;
text-align: center;
/* Fluid font size between 10px and 14px */
font-size: clamp(10px, 1vw, 14px);
}
table th {
background-color: #007bff;
color: white;
font-weight: bold;
}
table tr:nth-child(even) {
background-color: #f2f2f2;
}
table tr:hover {
background-color: #ddd;
}
.download-btn {
display: inline-block;
padding: 10px 15px;
background-color: #28a745;
color: white;
text-decoration: none;
border-radius: 5px;
margin-top: 15px;
/* Fluid font size between 12px and 16px */
font-size: clamp(12px, 1.5vw, 16px);
}
.total-table {
width: 35%;
}
/* Responsive Design */
@media (max-width: 1024px) {
.info {
padding: 15px;
width: 80%;
}
.row2,
.row3 {
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.invoice-table th,
.invoice-table td {
font-size: 12px;
padding: 8px;
}
}
@media (max-width: 768px) {
.info {
width: 90%;
}
.row1,
.row2,
.row3 {
grid-template-columns: 1fr;
}
}
@media (max-width: 600px) {
.table-wrapper {
overflow-x: auto;
}
table {
min-width: 600px;
}
}
@media (max-width: 480px) {
body {
max-width: 100%;
padding: 10px;
}
.info {
padding: 10px;
width: 100%;
}
table th,
table td {
font-size: 10px;
padding: 6px;
}
}
@media (max-width: 360px) {
h2 {
font-size: 20px;
margin-bottom: 15px;
}
.info {
width: 100%;
padding: 8px;
gap: 10px;
}
input,
textarea,
select {
font-size: 14px;
padding: 8px;
}
table th,
table td {
font-size: 8px;
padding: 4px;
}
.total-table {
width: 100%;
}
.download-btn {
padding: 8px 12px;
font-size: 14px;
}
}

View File

@@ -0,0 +1,111 @@
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background-color: #f9f9f9;
}
.container {
max-width: 500px;
width: 90%;
background: #ffffff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
text-align: center;
}
h1 {
margin-bottom: 20px;
color: #333;
}
form {
margin-bottom: 20px;
}
input[type="file"] {
display: block;
margin: 0 auto 15px auto;
font-size: 18px;
padding: 10px;
cursor: pointer;
border: 2px solid #007bff;
border-radius: 5px;
background-color: #f4f4f4;
}
input[type="file"]:hover {
border-color: #0056b3;
}
button {
background-color: #4CAF50;
color: white;
border: none;
padding: 15px 25px;
font-size: 18px;
border-radius: 5px;
cursor: pointer;
}
button:hover {
background-color: #45a049;
}
/* Style for the Back Button */
.back-button {
background-color: red;
color: white;
padding: 10px 20px;
text-decoration: none;
font-weight: bold;
border-radius: 5px;
display: inline-block;
margin-top: 20px;
text-align: center;
}
.back-button:hover {
background-color: darkred;
}
@media screen and (max-width: 600px) {
.container {
padding: 15px;
}
h1 {
font-size: 20px;
}
input[type="file"] {
font-size: 16px;
padding: 8px;
}
button, .back-button {
font-size: 14px;
padding: 10px 20px;
}
}
@media screen and (max-width: 360px) {
.container {
width: 95%;
padding: 10px;
}
h1 {
font-size: 18px;
margin-bottom: 15px;
}
input[type="file"] {
font-size: 14px;
padding: 6px;
}
button, .back-button {
font-size: 12px;
padding: 8px 16px;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

87
static/js/block.js Normal file
View File

@@ -0,0 +1,87 @@
window.onload = function () {
document.getElementById('block_Name').focus();
};
$(document).ready(function () {
$("#block_Name").on("input", function () {
let blockName = $(this).val();
let cleanedName = blockName.replace(/[^A-Za-z ]/g, "");
$(this).val(cleanedName);
});
$("#block_Name, #district_Id").on("input change", function () {
let blockName = $("#block_Name").val().trim();
let districtId = $("#district_Id").val();
if (blockName === "" || districtId === "") {
$("#blockMessage").text("").css("color", "");
$("#submitButton").prop("disabled", true);
return;
}
$.ajax({
url: "/check_block",
type: "POST",
contentType: "application/json",
data: JSON.stringify({ block_Name: blockName, district_Id: districtId }),
success: function (response) {
if (response.status === "available") {
$("#blockMessage").text(response.message).css("color", "green");
$("#submitButton").prop("disabled", false);
}
},
error: function (xhr) {
if (xhr.status === 409) {
$("#blockMessage").text("Block already exists!").css("color", "red");
$("#submitButton").prop("disabled", true);
} else if (xhr.status === 400) {
$("#blockMessage").text("Invalid block name! Only letters are allowed.").css("color", "red");
$("#submitButton").prop("disabled", true);
}
}
});
});
$("#blockForm").on("submit", function (event) {
event.preventDefault();
$.ajax({
url: "/add_block",
type: "POST",
data: $(this).serialize(),
success: function (response) {
alert(response.message);
location.reload();
},
error: function (xhr) {
alert(xhr.responseJSON.message);
}
});
});
$('#state_Id').change(function() {
var stateId = $(this).val();
if (stateId) {
$.ajax({
url: '/get_districts/' + stateId,
type: 'GET',
success: function(data) {
var districtDropdown = $('#district_Id');
districtDropdown.empty();
districtDropdown.append('<option value="" disabled selected>Select District</option>');
data.districts.forEach(function(district) {
districtDropdown.append('<option value="' + district.District_id + '">' + district.District_Name + '</option>');
});
districtDropdown.prop('disabled', false);
},
error: function() {
alert('Error fetching districts. Please try again.');
}
});
} else {
$('#district_Id').prop('disabled', true);
}
});
});

62
static/js/district.js Normal file
View File

@@ -0,0 +1,62 @@
window.onload = function () {
document.getElementById('district_Name').focus();
};
$(document).ready(function () {
$("#district_Name").on("input", function () {
let districtName = $(this).val();
// Remove numbers and special characters automatically
let cleanedName = districtName.replace(/[^A-Za-z ]/g, "");
$(this).val(cleanedName);
});
$("#district_Name, #state_Id").on("input change", function () {
let districtName = $("#district_Name").val().trim();
let stateId = $("#state_Id").val();
if (districtName === "" || stateId === "") {
$("#districtMessage").text("").css("color", "");
$("#submitButton").prop("disabled", true);
return;
}
$.ajax({
url: "/check_district",
type: "POST",
contentType: "application/json",
data: JSON.stringify({ district_Name: districtName, state_Id: stateId }),
success: function (response) {
if (response.status === "available") {
$("#districtMessage").text(response.message).css("color", "green");
$("#submitButton").prop("disabled", false);
}
},
error: function (xhr) {
if (xhr.status === 409) {
$("#districtMessage").text("District already exists!").css("color", "red");
$("#submitButton").prop("disabled", true);
} else if (xhr.status === 400) {
$("#districtMessage").text("Invalid district name! Only letters are allowed.").css("color", "red");
$("#submitButton").prop("disabled", true);
}
}
});
});
$("#districtForm").on("submit", function (event) {
event.preventDefault();
$.ajax({
url: "/add_district",
type: "POST",
data: $(this).serialize(),
success: function (response) {
alert(response.message);
location.reload();
},
error: function (xhr) {
alert(xhr.responseJSON.message);
}
});
});
});

View File

@@ -0,0 +1,18 @@
$("#updateHoldTypeForm").on("submit", function(event) {
event.preventDefault();
let holdTypeId = $("#hold_type_id").val();
let newHoldType = $("#edit_hold_type").val().trim();
let reg = /^[A-Za-z]/;
if (!reg.test(newHoldType)) {
alert("Hold Type must start with a letter.");
return;
}
$.post(`/update_hold_type/${holdTypeId}`, { hold_type: newHoldType }, function(response) {
alert(response.message);
window.location.href = "/";
}).fail(function(xhr) {
alert(xhr.responseJSON.message);
});
});

95
static/js/holdAmount.js Normal file
View File

@@ -0,0 +1,95 @@
$(document).ready(function () {
// Create a module to manage hold amounts
window.holdAmountModule = {
holdCount: 0,
holdTypes: [],
init: function() {
this.loadHoldTypes();
this.setupEventListeners();
},
loadHoldTypes: function() {
$.ajax({
url: '/get_hold_types',
method: 'GET',
dataType: 'json',
success: (data) => {
this.holdTypes = data;
$("#add_hold_amount").prop('disabled', false);
},
error: (err) => {
console.error('Failed to load hold types', err);
}
});
},
setupEventListeners: function() {
$("#add_hold_amount").click(() => this.addHoldAmountField());
$(document).on("click", ".remove-hold", (e) => this.removeHoldAmountField(e));
$(document).on("change", ".hold-type-dropdown", () => this.refreshDropdowns());
$(document).on("input", "input[name='hold_amount[]']", () => this.triggerHoldAmountChanged());
},
addHoldAmountField: function() {
this.holdCount++;
$("#hold_amount_container").append(`
<div class="hold-amount-field" id="hold_${this.holdCount}">
<select name="hold_type[]" class="hold-type-dropdown" required>
${this.generateOptions()}
</select>
<input type="number" step="0.01" name="hold_amount[]"
class="hold-amount-input" placeholder="Hold Amount" required>
<button type="button" class="remove-hold" data-id="hold_${this.holdCount}">X</button>
</div>
`);
this.refreshDropdowns();
this.triggerHoldAmountChanged();
},
removeHoldAmountField: function(e) {
const id = $(e.target).attr("data-id");
$(`#${id}`).remove();
this.refreshDropdowns();
this.triggerHoldAmountChanged();
},
generateOptions: function(selectedForThisDropdown = '') {
const selectedValues = $("select[name='hold_type[]']").map(function() {
return $(this).val();
}).get();
let options = '<option value="">Select Hold Type</option>';
this.holdTypes.forEach((type) => {
if (!selectedValues.includes(type.hold_type) || type.hold_type === selectedForThisDropdown) {
options += `<option value="${type.hold_type}">${type.hold_type}</option>`;
}
});
return options;
},
refreshDropdowns: function() {
$("select[name='hold_type[]']").each(function() {
const currentVal = $(this).val();
$(this).html(window.holdAmountModule.generateOptions(currentVal));
$(this).val(currentVal);
});
},
getTotalHoldAmount: function() {
let total = 0;
$("input[name='hold_amount[]']").each(function() {
total += parseFloat($(this).val()) || 0;
});
return total;
},
triggerHoldAmountChanged: function() {
const event = new Event('holdAmountChanged');
document.dispatchEvent(event);
}
};
// Initialize the module
window.holdAmountModule.init();
});

39
static/js/hold_types.js Normal file
View File

@@ -0,0 +1,39 @@
$(document).ready(function () {
$("#hold_type").on("input", function () {
let holdType = $(this).val().replace(/^\s+/, "");
$(this).val(holdType);
let reg = /^[A-Za-z]/;
if (!reg.test(holdType)) {
$("#holdTypeMessage").text("Hold Type must start with a letter.").css("color", "red");
$("#addButton").prop("disabled", true);
return;
} else {
$("#holdTypeMessage").text("").css("color", "");
$("#addButton").prop("disabled", false);
}
});
$("#holdTypeForm").on("submit", function (event) {
event.preventDefault();
$.post("/add_hold_type", $(this).serialize(), function (response) {
alert(response.message);
location.reload();
}).fail(function (xhr) {
alert(xhr.responseJSON.message);
});
});
$(".delete-button").on("click", function () {
let id = $(this).data("id");
if (confirm("Are you sure?")) {
$.post(`/delete_hold_type/${id}`, function (response) {
alert(response.message);
location.reload();
}).fail(function (xhr) {
alert(xhr.responseJSON.message);
});
}
});
});

62
static/js/invoice.js Normal file
View File

@@ -0,0 +1,62 @@
// Subcontractor autocomplete functionality
$(document).ready(function () {
$("#subcontractor").keyup(function () {
let query = $(this).val();
if (query !== "") {
$.ajax({
url: "/search_subcontractor",
method: "POST",
data: { query: query },
success: function (data) {
$("#subcontractor_list").fadeIn().html(data);
}
});
} else {
$("#subcontractor_list").fadeOut();
}
});
$(document).on("click", "li", function () {
$("#subcontractor").val($(this).text());
$("#subcontractor_id").val($(this).attr("data-id"));
$("#subcontractor_list").fadeOut();
});
});
// Success Alert: show alert and reload after 3 seconds
function showSuccessAlert() {
const alertBox = document.getElementById("invoiceSuccessAlert");
alertBox.classList.add("show");
setTimeout(() => {
alertBox.classList.remove("show");
// Reload page or redirect after alert hides
window.location.href = '/add_invoice';
}, 3000);
}
// Submit form via AJAX
$("#invoiceForm").on("submit", function (e) {
e.preventDefault();
let formData = $(this).serialize();
$.ajax({
url: '/add_invoice',
method: 'POST',
data: formData,
success: function (response) {
if(response.status === "success") {
showSuccessAlert();
} else {
alert(response.message);
}
},
error: function (xhr, status, error) {
alert("Submission failed: " + error);
}
});
});
window.onload = function () {
document.getElementById('subcontractor').focus();
};

View File

@@ -0,0 +1,39 @@
document.addEventListener('DOMContentLoaded', function () {
const form = document.getElementById('saveForm');
form.addEventListener('submit', function (e) {
e.preventDefault(); // Prevent normal form submission
const formData = new FormData(form);
fetch('/save_data', {
method: 'POST',
body: formData,
}).then(response => response.json()).then(data => {
if (data.success) {
Swal.fire({
icon: 'success',
title: 'Success!',
text: data.success,
showConfirmButton: true,
confirmButtonText: 'OK'
}).then(() => {
const redirectUrl = "{{ url_for('upload_excel_file') }}"; // Redirect after success pop
});
} else if (data.error) {
Swal.fire({
icon: 'error',
title: 'Error!',
text: data.error,
});
}
}).catch(error => {
Swal.fire({
icon: 'error',
title: 'Error!',
text: 'An unexpected error occurred.',
});
console.error('Error:', error);
});
});
});

View File

@@ -0,0 +1,21 @@
$("#saveForm").on("submit", function (event) {
event.preventDefault();
$.ajax({
url: "/save_data",
type: "POST",
data: $(this).serialize(),
success: function (response) {
if (response.success) {
alert("Success: " + response.success); // Show success alert
window.location.href = "/upload_excel_file"; // Redirect to the upload page
}
},
error: function (xhr) {
if (xhr.responseJSON && xhr.responseJSON.error) {
alert("Error: " + xhr.responseJSON.error);
} else {
alert("An unexpected error occurred. Please try again.");
}
}
});
});

View File

@@ -0,0 +1,43 @@
$(document).ready(function () {
function fetchResults() {
let formData = $('#search-form').serialize();
$.ajax({
type: 'POST',
url: '/search_contractor',
data: formData,
success: function (data) {
let tableBody = $('#result-table tbody');
tableBody.empty();
if (data.length === 0) {
tableBody.append('<tr><td colspan="6">No data found</td></tr>');
} else {
data.forEach(function (row) {
tableBody.append(`
<tr>
<td><a href="/contractor_report/${row.Contractor_Id}" target="_blank">${row.Contractor_Name}</a></td>
<td><a href="/pmc_report/${row.PMC_No}" target="_blank">${row.PMC_No}</a></td>
<td>${row.State_Name}</td>
<td>${row.District_Name}</td>
<td>${row.Block_Name}</td>
<td>${row.Village_Name}</td>
</tr>
`);
});
}
},
error: function (xhr) {
alert(xhr.responseJSON.error);
}
});
}
$('#search-form input').on('keyup change', function () {
fetchResults();
});
});
window.onload = function () {
document.getElementById('subcontractor_name').focus();
};

View File

@@ -0,0 +1,108 @@
// Search on table using search inpute options
function searchTable() {
let input = document.getElementById("searchBar").value.toLowerCase();
let rows = document.querySelectorAll("table tbody tr");
rows.forEach(row => {
let blockName = row.cells[1].textContent.toLowerCase();
let districtName = row.cells[2].textContent.toLowerCase();
let villageName = row.cells[3].textContent.toLowerCase();
if (blockName.includes(input) || districtName.includes(input)|| villageName.includes(input)) {
row.style.display = "";
} else {
row.style.display = "none";
}
});
}
// Common Sorting Script for Tables
function sortTable(n, dir) {
var table, rows, switching, i, x, y, shouldSwitch;
table = document.getElementById("sortableTable"); // Ensure your table has this ID
switching = true;
while (switching) {
switching = false;
rows = table.rows;
for (i = 1; i < (rows.length - 1); i++) {
shouldSwitch = false;
x = rows[i].getElementsByTagName("TD")[n];
y = rows[i + 1].getElementsByTagName("TD")[n];
if (dir == "asc") {
if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) {
shouldSwitch = true;
break;
}
} else if (dir == "desc") {
if (x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase()) {
shouldSwitch = true;
break;
}
}
}
if (shouldSwitch) {
rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
switching = true;
}
}
}
// Attach sorting functionality to all sortable tables
document.addEventListener("DOMContentLoaded", function() {
// Find all elements with the class "sortable-header"
var sortableHeaders = document.querySelectorAll(".sortable-header");
sortableHeaders.forEach(function(header) {
// Attach click event for ascending sort
if (header.querySelector(".sort-asc")) {
header.querySelector(".sort-asc").addEventListener("click", function() {
var columnIndex = Array.from(header.parentNode.children).indexOf(header);
sortTable(columnIndex, "asc");
});
}
// Attach click event for descending sort
if (header.querySelector(".sort-desc")) {
header.querySelector(".sort-desc").addEventListener("click", function() {
var columnIndex = Array.from(header.parentNode.children).indexOf(header);
sortTable(columnIndex, "desc");
});
}
});
});
// ADD & Dispaly screen show
document.addEventListener("DOMContentLoaded", function () {
const addButton = document.getElementById("addButton");
const displayButton = document.getElementById("displayButton");
const addForm = document.getElementById("addForm");
const addTable = document.getElementById("addTable");
// Show "Add State" form by default
addForm.style.display = "block";
addButton.classList.add("active-button"); // Optional: Add styling for active button
addButton.addEventListener("click", function () {
addForm.style.display = "block";
addTable.style.display = "none";
addButton.classList.add("active-button");
displayButton.classList.remove("active-button");
});
displayButton.addEventListener("click", function () {
addForm.style.display = "none";
addTable.style.display = "block";
displayButton.classList.add("active-button");
addButton.classList.remove("active-button");
});
});

View File

@@ -0,0 +1,8 @@
function showSuccessAlert(event) {
event.preventDefault(); // Prevent form submission
document.getElementById("successPopup").style.display = "block";
setTimeout(function() {
document.getElementById("successPopup").style.display = "none";
event.target.submit(); // Submit the form after showing the message
}, 2000);
}

66
static/js/sorting.js Normal file
View File

@@ -0,0 +1,66 @@
$(document).ready(function () {
function fetchResults(sortBy = '', sortOrder = '') {
let formData = $('#search-form').serialize();
formData += &sort_by=${sortBy}&sort_order=${sortOrder};
$.ajax({
type: 'POST',
url: '/search_contractor',
data: formData,
success: function (data) {
let tableBody = $('#result-table tbody');
tableBody.empty();
if (data.length === 0) {
tableBody.append('<tr><td colspan="6">No data found</td></tr>');
} else {
data.forEach(function (row) {
tableBody.append(`
<tr>
<td><a href="/contractor_report/${row.Contractor_Id}" target="_blank">${row.Contractor_Name}</a></td>
<td><a href="/pmc_report/${row.PMC_No}" target="_blank">${row.PMC_No}</a></td>
<td>${row.State_Name}</td>
<td>${row.District_Name}</td>
<td>${row.Block_Name}</td>
<td>${row.Village_Name}</td>
</tr>
`);
});
}
},
error: function (xhr) {
alert(xhr.responseJSON.error);
}
});
}
$('#search-form input').on('keyup change', function () {
fetchResults();
});
function showSortOptions(thElement, column) {
let sortMenu = $('#sort-options');
let offset = $(thElement).position();
let thHeight = $(thElement).outerHeight();
sortMenu.html(`
<button onclick="fetchResults('${column}', 'ASC')">Ascending</button>
<button onclick="fetchResults('${column}', 'DESC')">Descending</button>
`);
sortMenu.css({
display: 'block',
top: offset.top + thHeight + 'px',
left: offset.left + 'px'
});
}
$(document).click(function(event) {
if (!$(event.target).closest('.sort-options, th').length) {
$('#sort-options').hide();
}
});
window.fetchResults = fetchResults;
window.showSortOptions = showSortOptions;
});

61
static/js/state.js Normal file
View File

@@ -0,0 +1,61 @@
window.onload = function () {
document.getElementById('state_Name').focus();
};
$(document).ready(function () {
$("#state_Name").on("input", function () {
let stateName = $(this).val();
// Remove numbers and special characters automatically
let cleanedName = stateName.replace(/[^A-Za-z ]/g, "");
$(this).val(cleanedName);
});
$("#state_Name").on("input", function () {
let stateName = $("#state_Name").val().trim();
if (stateName === "") {
$("#stateMessage").text("").css("color", "");
$("#submitButton").prop("disabled", true);
return;
}
$.ajax({
url: "/check_state",
type: "POST",
contentType: "application/json",
data: JSON.stringify({ state_Name: stateName }),
success: function (response) {
if (response.status === "available") {
$("#stateMessage").text(response.message).css("color", "green");
$("#submitButton").prop("disabled", false);
}
},
error: function (xhr) {
if (xhr.status === 409) {
$("#stateMessage").text("State already exists!").css("color", "red");
$("#submitButton").prop("disabled", true);
} else if (xhr.status === 400) {
$("#stateMessage").text("Invalid state name! Only letters are allowed.").css("color", "red");
$("#submitButton").prop("disabled", true);
}
}
});
});
$("#stateForm").on("submit", function (event) {
event.preventDefault();
$.ajax({
url: "/add_state",
type: "POST",
data: $(this).serialize(),
success: function (response) {
alert(response.message);
location.reload();
},
error: function (xhr) {
alert(xhr.responseJSON.message);
}
});
});
});

View File

@@ -0,0 +1,49 @@
function validateInput() {
let isValid = true;
// Get form elements
let contractorName = document.getElementById("Contractor_Name").value;
let mobileNo = document.getElementById("Mobile_No").value;
let panNo = document.getElementById("PAN_No").value;
let email = document.getElementById("Email").value;
let passwordField = document.getElementById("Contractor_password");
let submitBtn = document.getElementById("submitBtn");
// Validation patterns
let mobileRegex = /^[0-9]{10}$/;
let panRegex = /^[A-Z0-9]{10}$/;
let emailRegex = /^[a-z]+@[a-z]+\.[a-z]{2,6}$/;
// Validate Mobile No
if (!mobileNo.match(mobileRegex)) {
document.getElementById("mobileError").innerText = "Mobile No must be exactly 10 digits.";
isValid = false;
} else {
document.getElementById("mobileError").innerText = "";
}
// Validate PAN No
if (!panNo.match(panRegex)) {
document.getElementById("panError").innerText = "PAN No must be uppercase letters or digits (10 chars).";
isValid = false;
} else {
document.getElementById("panError").innerText = "";
}
// Validate Email
if (!email.match(emailRegex)) {
document.getElementById("emailError").innerText = "Email must be lowercase, contain '@' and '.'";
isValid = false;
} else {
document.getElementById("emailError").innerText = "";
}
// Enable or disable the submit button
submitBtn.disabled = !isValid;
}
window.onload = function () {
document.getElementById('Contractor_Name').focus();
};

View File

@@ -0,0 +1,12 @@
function validateFileInput() {
const fileInput = document.querySelector('input[type="file"]');
const filePath = fileInput.value;
const allowedExtensions = /(\.xlsx|\.xls)$/i;
if (!allowedExtensions.exec(filePath)) {
alert("Please upload a valid Excel file (.xlsx or .xls only).");
fileInput.value = '';
return false;
}
return true;
}

102
static/js/village.js Normal file
View File

@@ -0,0 +1,102 @@
window.onload = function () {
document.getElementById('Village_Name').focus();
};
$(document).ready(function () {
$('#state_Id').change(function () {
var stateId = $(this).val();
if (stateId) {
$.ajax({
url: '/get_districts/' + stateId,
type: 'GET',
success: function (data) {
var districtDropdown = $('#district_Id');
districtDropdown.empty().append('<option value="" disabled selected>Select District</option>');
data.districts.forEach(function (district) {
districtDropdown.append('<option value="' + district.District_id + '">' + district.District_Name + '</option>');
});
districtDropdown.prop('disabled', false);
}
});
}
});
$('#district_Id').change(function () {
var districtId = $(this).val();
if (districtId) {
$.ajax({
url: '/get_blocks/' + districtId,
type: 'GET',
success: function (data) {
var blockDropdown = $('#block_Id');
blockDropdown.empty().append('<option value="" disabled selected>Select Block</option>');
data.blocks.forEach(function (block) {
blockDropdown.append('<option value="' + block.Block_Id + '">' + block.Block_Name + '</option>');
});
blockDropdown.prop('disabled', false);
}
});
}
});
$('#Village_Name').on('input', function () {
var villageName = $(this).val();
var validPattern = /^[A-Za-z ]*$/;
if (!validPattern.test(villageName)) {
$('#villageMessage').text('Only letters and spaces are allowed!').css('color', 'red');
$('#submitVillage').prop('disabled', true);
} else {
$('#villageMessage').text('');
$('#submitVillage').prop('disabled', false);
}
});
$('#Village_Name, #block_Id').on('change keyup', function () {
var blockId = $('#block_Id').val();
var villageName = $('#Village_Name').val().trim();
if (blockId && villageName) {
$.ajax({
url: '/check_village',
type: 'POST',
data: { block_Id: blockId, Village_Name: villageName },
success: function (response) {
if (response.status === 'exists') {
$('#villageMessage').text(response.message).css('color', 'red');
$('#submitVillage').prop('disabled', true);
} else {
$('#villageMessage').text(response.message).css('color', 'green');
$('#submitVillage').prop('disabled', false);
}
},
error: function () {
$('#villageMessage').text('Error checking village name').css('color', 'red');
$('#submitVillage').prop('disabled', true);
}
});
}
});
$('#villageForm').submit(function (event) {
event.preventDefault(); // Prevent default form submission
$.ajax({
url: '/add_village',
type: 'POST',
data: $(this).serialize(),
success: function (response) {
if (response.status === 'success') {
alert('Village added successfully!');
location.reload(); // Refresh the page to show the updated list
} else {
alert('Error adding village. Please try again.');
}
},
error: function () {
alert('An error occurred. Please try again.');
}
});
});
});

97
templates/add_block.html Normal file
View File

@@ -0,0 +1,97 @@
{% extends 'base.html' %}
{% block content %}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Add Block</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/block.js') }}"></script>
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
</head>
<body>
<!-- Button Container to Center Buttons -->
<div class="button-container">
<button id="addButton" class="action-button">Add</button>
<button id="displayButton" class="action-button">Display</button>
</div>
<div id="addForm" style="display: none;">
<div class="container">
<div class="form-block">
<h2>Create a New Block</h2>
<form id="blockForm" method="POST">
<!-- Select State Dropdown -->
<label for="state_Id">State:</label>
<select id="state_Id" name="state_Id" required>
<option value="" disabled selected>Select State</option>
{% for state in states %}
<option value="{{ state[0] }}">{{ state[1] }}</option>
{% endfor %}
</select>
<!-- Select District Dropdown -->
<label for="district_Id">District:</label>
<select id="district_Id" name="district_Id" required disabled>
<option value="" disabled selected>Select District</option>
</select>
<!-- Block Name Input -->
<label for="block_Name">Enter Block Name:</label>
<input type="text" id="block_Name" name="block_Name" placeholder="Block Name" required>
<span id="blockMessage"></span>
<button type="submit" id="submitButton" disabled>Add Block</button>
</form>
</div>
</div>
</div>
<div id="addTable" style="display: none;">
<div class="search-container">
<h2>Display Blocks</h2>
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
</div>
<!-- Display Blocks -->
<table id="sortableTable" border="1">
<tr>
<th>Block Sr no</th>
<th class="sortable-header">Block Name
<span class="sort-buttons">
<span class="sort-asc">⬆️</span>
<span class="sort-desc">⬇️</span>
</span>
</th>
<th class="sortable-header">District Name
<span class="sort-buttons">
<span class="sort-asc">⬆️</span>
<span class="sort-desc">⬇️</span>
</span>
</th>
<th>Update</th>
<th>Delete</th>
</tr>
{% for block in block_data %}
<tr>
<td>{{ block[0] }}</td>
<td>{{ block[1] }}</td>
<td>{{ block[2] }}</td>
<td>
<a href="{{ url_for('edit_block', block_id=block[0]) }}">
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit"
class="icon">
</a>
</td>
<td>
<a href="{{ url_for('delete_block', block_id=block[0]) }}"
onclick="return confirm('Are you sure you want to delete this block?');">
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete"
class="icon">
</a>
</td>
</tr>
{% endfor %}
</table>
</div>
</body>
{% endblock %}

View File

@@ -0,0 +1,85 @@
{% extends 'base.html' %}
{% block content %}
<head>
<title>Add District</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/district.js') }}"></script>
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
</head>
<body>
<!-- Button Container to Center Buttons -->
<div class="button-container">
<button id="addButton" class="action-button">Add</button>
<button id="displayButton" class="action-button">Display</button>
</div>
<div id="addForm" style="display: none;">
<h2>Add District</h2>
<form id="districtForm" method="POST">
<label for="state_Id">State :</label>
<select name="state_Id" id="state_Id" required>
<option value="" disabled selected>Select State</option>
{% for state in states %}
<option value="{{ state[0] }}">{{ state[1] }}</option>
{% endfor %}
</select>
<label>Enter District :</label>
<input type="text" id="district_Name" name="district_Name" placeholder="District Name" required>
<span id="districtMessage"></span>
<button type="submit" id="submitButton" disabled>Add District</button>
</form>
</div>
<div id="addTable" style="display: none;">
<div class="search-container">
<h2>Display Districts</h2>
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
</div>
<table id="sortableTable" border="1">
<tr>
<th>District ID</th>
<th class="sortable-header">
District Name
<span class="sort-buttons">
<span class="sort-asc">⬆️</span>
<span class="sort-desc">⬇️</span>
</span></th>
<th class="sortable-header">
State Name
<span class="sort-buttons">
<span class="sort-asc">⬆️</span>
<span class="sort-desc">⬇️</span>
</span></th>
<th>Edit District</th>
<th>Delete District</th>
</tr>
{% for district in districtdata %}
<tr>
<td>{{ district[0] }}</td>
<td>{{ district[1] }}</td>
<td>{{ district[2] }}</td>
<td>
<a href="{{ url_for('edit_district', district_id=district[0]) }}">
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit"
class="icon">
</a>
</td>
<td>
<a href="{{ url_for('delete_district', district_id=district[0]) }}"
onclick="return confirm('Are you sure you want to delete this district?')">
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete"
class="icon">
</a>
</td>
</tr>
{% endfor %}
</table>
</div>
</body>
{% endblock %}

View File

@@ -0,0 +1,165 @@
{% extends 'base.html' %}
{% block content %}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Add GST Release</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
<script src="{{ url_for('static', filename='js/invoice.js') }}"></script>
</head>
<body>
<!-- Button Container to Center Buttons -->
<div class="button-container">
<button id="addButton" class="action-button">Add</button>
<button id="displayButton" class="action-button">Display</button>
</div>
<div id="addForm" style="display: none;">
<h2>Add GST Release</h2>
<form action="/add_gst_release" method="POST" onsubmit="showSuccessAlert(event)">
<div class="row1">
<div>
<label for="subcontractor">Subcontractor Name:</label>
<input type="text" id="subcontractor" name="subcontractor" required autocomplete="off"/>
<input type="hidden" id="subcontractor_id" name="subcontractor_id"/>
<div id="subcontractor_list" class="autocomplete-items"></div>
</div>
</div>
<label for="PMC_No">PMC No:</label><br>
<select id="PMC_No" name="PMC_No" required>
<option value="">Select PMC No</option>
{% for option in pmc_options %}
<option value="{{ option.PMC_No }}">{{ option.PMC_No }} - {{ option.Subcontractor_Name }}</option>
{% endfor %}
</select><br><br>
<label for="invoice_No">Invoice No:</label><br>
<input type="text" id="invoice_No" name="invoice_No" required><br><br>
<label for="basic_amount">Amount:</label><br>
<input type="number" step="0.01" id="basic_amount" name="basic_amount" placeholder="₹ - 00.00" required><br><br>
<label for="final_amount">Total Amount:</label><br>
<input type="number" step="0.01" id="final_amount" name="final_amount" placeholder="₹ - 00.00" required><br><br>
<button type="submit">Submit GST Release</button>
</form>
</div>
<!-- Success Popup -->
<div id="successPopup" class="success-popup">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}">
<i>&#10004;</i> {{ message }}
</div>
{% endfor %}
{% endif %}
{% endwith %}
</div>
<div id="addTable" style="display: none;">
<div class="search-container">
<h2>GST Release History</h2>
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
</div>
<table id="sortableTable" border="1">
<thead>
<tr>
<th class="sortable-header">GST_Release_Id</th>
<th class="sortable-header">PMC_No</th>
<th>Invoice_No</th>
<th>Basic_Amount</th>
<th>Final_Amount</th>
<th>Update</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{% for gst_rel in gst_releases %}
<tr>
<td>{{ gst_rel[0] }}</td>
<td>{{ gst_rel[1] }}</td>
<td>{{ gst_rel[2] }}</td>
<td>{{ gst_rel[3] }}</td>
<td>{{ gst_rel[4] }}</td>
<td>
<a href="/edit_gst_release/{{ gst_rel[0] }}">
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit"
class="icon">
</a>
</td>
<td>
<a href="/delete_gst_release/{{ gst_rel[0] }}"
onclick="return confirm('Are you sure you want to delete this GST Release?')">
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete"
class="icon">
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Handle subcontractor autocomplete
document.getElementById("subcontractor").addEventListener("input", function () {
const query = this.value;
const list = document.getElementById("subcontractor_list");
if (query.length < 2) {
list.innerHTML = '';
return;
}
fetch(`/search_subcontractor?query=${encodeURIComponent(query)}`)
.then(response => response.json())
.then(data => {
list.innerHTML = '';
data.results.forEach(item => {
const div = document.createElement("div");
div.setAttribute("data-id", item.id);
div.textContent = item.name;
list.appendChild(div);
});
});
});
// Handle subcontractor selection
document.getElementById("subcontractor_list").addEventListener("click", function (e) {
const selectedId = e.target.getAttribute("data-id");
const selectedName = e.target.textContent;
if (selectedId) {
document.getElementById("subcontractor_id").value = selectedId;
document.getElementById("subcontractor").value = selectedName;
document.getElementById("subcontractor_list").innerHTML = "";
// Update PMC dropdown for selected subcontractor
fetch(`/get_pmc_nos_by_subcontractor/${encodeURIComponent(selectedId)}`)
.then(response => response.json())
.then(data => {
const pmcDropdown = document.getElementById("PMC_No");
pmcDropdown.innerHTML = '<option value="">Select PMC No</option>';
data.pmc_nos.forEach(pmc => {
const option = document.createElement("option");
option.value = pmc;
option.textContent = pmc;
pmcDropdown.appendChild(option);
});
});
}
});
});
</script>
<script src="{{ url_for('static', filename='js/showSuccessAlert.js') }}"></script>
</body>
{% endblock %}

View File

@@ -0,0 +1,59 @@
{% extends 'base.html' %}
{% block content %}
<head>
<title>Manage Hold Types</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="{{ url_for('static', filename='js/hold_types.js') }}"></script>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
</head>
<body>
<div class="button-container">
<button id="addButton" class="action-button">Add</button>
<button id="displayButton" class="action-button">Display</button>
</div>
<div id="addForm" style="display: none;">
<h2>Add Hold Types</h2>
<form id="holdTypeForm" method="POST">
<label>Enter Hold Amount Type:</label>
<input type="text" id="hold_type" name="hold_type" placeholder="Enter Type" required>
<span id="holdTypeMessage"></span>
<button type="submit" value="Add Hold Type" id="successPopup">Add Hold Type</button>
</form>
</div>
<div id="addTable" style="display: none;">
<div class="search-container">
<h2>Hold Type List</h2>
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
</div>
<table id="sortableTable" border="1">
<tr>
<th>ID</th>
<th class="sortable-header">
Hold Type
<span class="sort-buttons">
<span class="sort-asc">⬆️</span>
<span class="sort-desc">⬇️</span>
</span>
</th>
<th>Update</th>
<th>Delete</th>
</tr>
{% for htd in Hold_Types_data %}
<tr>
<td>{{ htd['hold_type_id'] }}</td>
<td>{{ htd['hold_type'] }}</td>
<td><a href="{{ url_for('update_hold_type', id=htd['hold_type_id']) }}">Edit</a></td>
<td><button class="delete-button" data-id="{{ htd['hold_type_id'] }}">Delete</button></td>
</tr>
{% endfor %}
</table>
<a href="/">Back to Dashboard</a>
</div>
</body>
{% endblock %}

369
templates/add_invoice.html Normal file
View File

@@ -0,0 +1,369 @@
{% extends 'base.html' %}
{% block content %}
<head xmlns="http://www.w3.org/1999/html">
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Add Invoice</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/invoice.css') }}">
<script src="{{ url_for('static', filename='js/invoice.js') }}"></script>
<script src="{{ url_for('static', filename='js/holdAmount.js') }}"></script>
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
</head>
<body>
{% if success == 'true' %}
<div class="alert alert-success alert-dismissible fade show mt-3" role="alert">
✅ Invoice added successfully!
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endif %}
<!-- Flash Messages -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<div class="flash-messages">
{% for category, message in messages %}
<div class="alert {{ category }}">{{ message }}</div>
{% endfor %}
</div>
{% endif %}
{% endwith %}
<div class="button-container">
<button id="addButton" class="action-button">Add</button>
<button id="displayButton" class="action-button">Display</button>
</div>
<div id="addForm" style="display: none;">
<h2>Add Invoice</h2>
<form id="invoiceForm" action="{{ url_for('add_invoice') }}" method="POST">
<div class="row1">
<div>
<label for="subcontractor">Subcontractor Name:</label>
<input type="text" id="subcontractor" name="subcontractor" required autocomplete="off"/>
<input type="hidden" id="subcontractor_id" name="subcontractor_id"/>
<div id="subcontractor_list"></div>
</div>
</div>
<div class="row2">
<div>
<label for="village">Village Name:</label>
<select id="village" name="village" required>
<option value="">-- Select Village --</option>
{% for village in villages %}
<option value="{{ village.Village_Name }}">{{ village.Village_Name }}</option>
{% endfor %}
</select>
</div>
<div>
<label for="pmc_no">PMC No:</label>
<input type="text" id="pmc_no" name="pmc_no" required/>
<div id="pmc_no_list" class="autocomplete-list"></div>
</div>
</div>
<div class="row2">
<div>
<label for="work_type">Work Type:</label>
<input type="text" id="work_type" name="work_type" required/>
</div>
<div>
<label for="invoice_details">Invoice Details:</label>
<textarea id="invoice_details" name="invoice_details" required></textarea>
</div>
</div>
<div class="row2">
<div>
<label for="invoice_no">Invoice No:</label>
<input type="text" id="invoice_no" name="invoice_no" required/>
</div>
<div>
<label for="invoice_date">Invoice Date:</label>
<input type="date" id="invoice_date" name="invoice_date" required/>
</div>
</div>
<div class="row3">
<div>
<label for="basic_amount">Basic Amount:</label>
<input type="number" step="0.01" id="basic_amount" name="basic_amount" placeholder="₹ - 00.00" required/>
</div>
<div>
<label for="debit_amount">Debit Amount:</label>
<input type="number" step="0.01" id="debit_amount" name="debit_amount" placeholder="₹ - 00.00" required/>
</div>
<div>
<label for="after_debit_amount">After Debit Amount:</label>
<input type="number" step="0.01" id="after_debit_amount" name="after_debit_amount" placeholder="₹ - 00.00" readonly required/>
</div>
</div>
<div class="row3">
<div class="percentage-field">
<label for="gst_percentage">GST %:</label>
<input type="number" step="0.01" id="gst_percentage" name="gst_percentage" placeholder="%"/>
<label for="gst_amount">GST Amount:</label>
<input type="number" step="0.01" id="gst_amount" name="gst_amount" placeholder="₹ - 00.00" readonly required/>
</div>
<div>
<label for="amount">Amount:</label>
<input type="number" step="0.01" id="amount" name="amount" placeholder="₹ - 00.00" readonly required/>
</div>
<div class="percentage-field">
<label for="tds_percentage">TDS %:</label>
<input type="number" step="0.01" id="tds_percentage" name="tds_percentage" placeholder="%"/>
<label for="tds_amount">TDS Amount:</label>
<input type="number" step="0.01" id="tds_amount" name="tds_amount" placeholder="₹ - 00.00" readonly required/>
</div>
</div>
<div class="row3">
<div class="percentage-field">
<label for="sd_percentage">SD %:</label>
<input type="number" step="0.01" id="sd_percentage" name="sd_percentage" placeholder="%"/>
<label for="sd_amount">SD Amount:</label>
<input type="number" step="0.01" id="sd_amount" name="sd_amount" placeholder="₹ - 00.00" readonly required>
</div>
<div class="percentage-field">
<label for="commission_percentage">On Commission %:</label>
<input type="number" step="0.01" id="commission_percentage" name="commission_percentage" placeholder="%"/>
<label for="on_commission">On Commission:</label>
<input type="number" step="0.01" id="on_commission" name="on_commission" placeholder="₹ - 00.00" readonly required>
</div>
<div class="percentage-field">
<label for="hydro_percentage">Hydro Testing %:</label>
<input type="number" step="0.01" id="hydro_percentage" name="hydro_percentage" placeholder="%"/>
<label for="hydro_testing">Hydro Testing:</label>
<input type="number" step="0.01" id="hydro_testing" name="hydro_testing" placeholder="₹ - 00.00" readonly required>
</div>
</div>
<div class="hold-row">
<button type="button" id="add_hold_amount" class="button">+ Add Hold Amount</button>
</div>
<!-- Dynamically added hold amount fields -->
<div id="hold_amount_container"></div>
<div class="row2">
<div>
<label for="gst_sd_amount">GST SD Amount:</label>
<input type="number" step="0.01" id="gst_sd_amount" name="gst_sd_amount" placeholder="₹ - 00.00" required/>
</div>
<div>
<label for="final_amount">Final Amount:</label>
<input type="number" step="0.01" id="final_amount" name="final_amount" placeholder="₹ - 00.00" required/>
</div>
</div>
<button type="submit" class="button">Submit</button>
</form>
</div>
<div id="addTable" style="display: none;">
<!-- Invoice Table Section -->
<div class="search-container">
<h2>Invoice List</h2>
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
{% if invoices %}
<table class="invoice-table">
<thead>
<tr>
<th>Invoice Id</th>
<th>SubContractor Name</th>
<th>PMC No</th>
<th>Village</th>
<th>Work Type</th>
<th>Invoice Details</th>
<th>Invoice Date</th>
<th>Invoice No</th>
<th>Basic Amount</th>
<th>Debit Amount</th>
<th>After Debit Amount</th>
<th>Amount</th>
<th>GST Amount</th>
<th>TDS Amount</th>
<th>SD Amount</th>
<th>On Commission</th>
<th>Hydro Testing</th>
<th>GST SD Amount</th>
<th>Final Amount</th>
<th>Update</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{% for invoice in invoices %}
<tr>
<td>{{ invoice.Invoice_Id }}</td>
<td>{{ invoice.Contractor_Name }}</td>
<td>{{ invoice.PMC_No }}</td>
<td>{{ invoice.Village_Name or 'N/A' }}</td>
<td>{{ invoice.Work_Type }}</td>
<td>{{ invoice.Invoice_Details }}</td>
<td>{{ invoice.Invoice_Date }}</td>
<td>{{ invoice.Invoice_No }}</td>
<td>{{ invoice.Basic_Amount }}</td>
<td>{{ invoice.Debit_Amount }}</td>
<td>{{ invoice.After_Debit_Amount }}</td>
<td>{{ invoice.Amount }}</td>
<td>{{ invoice.GST_Amount }}</td>
<td>{{ invoice.TDS_Amount }}</td>
<td>{{ invoice.SD_Amount }}</td>
<td>{{ invoice.On_Commission }}</td>
<td>{{ invoice.Hydro_Testing }}</td>
<td>{{ invoice.GST_SD_Amount }}</td>
<td>{{ invoice.Final_Amount }}</td>
<td>
<a href="{{ url_for('edit_invoice', invoice_id=invoice.Invoice_Id) }}">
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit" class="icon">
</a>
</td>
<td>
<a href="{{ url_for('delete_invoice', invoice_id=invoice.Invoice_Id) }}"
onclick="return confirm('Are you sure?')">
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete" class="icon">
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>No invoices found.</p>
{% endif %}
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Get all the input fields
const basicAmount = document.getElementById('basic_amount');
const debitAmount = document.getElementById('debit_amount');
const afterDebitAmount = document.getElementById('after_debit_amount');
const amount = document.getElementById('amount');
// Percentage fields
const gstPercentage = document.getElementById('gst_percentage');
const gstAmount = document.getElementById('gst_amount');
const tdsPercentage = document.getElementById('tds_percentage');
const tdsAmount = document.getElementById('tds_amount');
const sdPercentage = document.getElementById('sd_percentage');
const sdAmountInput = document.getElementById('sd_amount');
const commissionPercentage = document.getElementById('commission_percentage');
const onCommission = document.getElementById('on_commission');
const hydroPercentage = document.getElementById('hydro_percentage');
const hydroTesting = document.getElementById('hydro_testing');
const gstSdAmount = document.getElementById('gst_sd_amount');
const finalAmount = document.getElementById('final_amount');
// Calculate after debit amount when basic or debit amount changes
function calculateAfterDebitAmount() {
const basic = parseFloat(basicAmount.value) || 0;
const debit = parseFloat(debitAmount.value) || 0;
const afterDebit = basic - debit;
afterDebitAmount.value = afterDebit.toFixed(2);
calculateGST();
}
// Calculate GST and Amount
function calculateGST() {
const baseAmount = parseFloat(afterDebitAmount.value) || 0;
if (gstPercentage.value) {
const gstPerc = parseFloat(gstPercentage.value) || 0;
const gstAmt = (baseAmount * gstPerc) / 100;
gstAmount.value = gstAmt.toFixed(2);
gstSdAmount.value = gstAmt.toFixed(2);
// Calculate Amount (After Debit + GST)
amount.value = (baseAmount + gstAmt).toFixed(2);
} else {
amount.value = baseAmount.toFixed(2);
}
calculateOtherDeductions();
}
// Calculate other deductions (TDS, SD, Commission, Hydro)
function calculateOtherDeductions() {
const baseAmount = parseFloat(afterDebitAmount.value) || 0;
// Calculate TDS
if (tdsPercentage.value) {
const tdsPerc = parseFloat(tdsPercentage.value) || 0;
const tdsAmt = (baseAmount * tdsPerc) / 100;
tdsAmount.value = tdsAmt.toFixed(2);
}
// Calculate SD
if (sdPercentage.value) {
const sdPerc = parseFloat(sdPercentage.value) || 0;
const sdAmt = (baseAmount * sdPerc) / 100;
sdAmountInput.value = sdAmt.toFixed(2);
}
// Calculate Commission
if (commissionPercentage.value) {
const commPerc = parseFloat(commissionPercentage.value) || 0;
const commAmt = (baseAmount * commPerc) / 100;
onCommission.value = commAmt.toFixed(2);
}
// Calculate Hydro Testing
if (hydroPercentage.value) {
const hydroPerc = parseFloat(hydroPercentage.value) || 0;
const hydroAmt = (baseAmount * hydroPerc) / 100;
hydroTesting.value = hydroAmt.toFixed(2);
}
calculateFinalAmount();
}
// Calculate final amount
function calculateFinalAmount() {
const amt = parseFloat(amount.value) || 0;
const tds = parseFloat(tdsAmount.value) || 0;
const sd = parseFloat(sdAmountInput.value) || 0;
const commission = parseFloat(onCommission.value) || 0;
const hydro = parseFloat(hydroTesting.value) || 0;
const gstSd = parseFloat(gstSdAmount.value) || 0;
// Get hold amounts
let totalHold = 0;
document.querySelectorAll('input[name="hold_amount[]"]').forEach(input => {
totalHold += parseFloat(input.value) || 0;
});
// Final Amount = Amount - TDS - SD - Commission - Hydro - GST SD - Hold Amounts
const final = amt - tds - sd - commission - hydro - gstSd - totalHold;
finalAmount.value = final.toFixed(2);
}
// Add event listeners
basicAmount.addEventListener('input', calculateAfterDebitAmount);
debitAmount.addEventListener('input', calculateAfterDebitAmount);
// Percentage fields
gstPercentage.addEventListener('input', calculateGST);
tdsPercentage.addEventListener('input', calculateOtherDeductions);
sdPercentage.addEventListener('input', calculateOtherDeductions);
commissionPercentage.addEventListener('input', calculateOtherDeductions);
hydroPercentage.addEventListener('input', calculateOtherDeductions);
// Listen for changes in hold amounts
document.addEventListener('holdAmountChanged', calculateFinalAmount);
});
// Optional JS for auto-hiding flash
setTimeout(() => {
document.querySelectorAll('.alert').forEach(el => el.style.display = 'none');
}, 5000);
</script>
</div>
</body>
{% endblock %}

182
templates/add_payment.html Normal file
View File

@@ -0,0 +1,182 @@
{% extends 'base.html' %}
{% block content %}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Add Payment</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
<script src="{{ url_for('static', filename='js/invoice.js') }}"></script>
</head>
<body>
<div class="button-container">
<button id="addButton" class="action-button">Add</button>
<button id="displayButton" class="action-button">Display</button>
</div>
<div id="addForm" style="display: none;">
<h2>Add Payment</h2>
<form action="/add_payment" method="POST" onsubmit="showSuccessAlert(event)">
<div class="row1">
<div>
<label for="subcontractor">Subcontractor Name:</label>
<input type="text" id="subcontractor" name="subcontractor" required autocomplete="off"/>
<input type="hidden" id="subcontractor_id" name="subcontractor_id"/>
<div id="subcontractor_list" class="autocomplete-items"></div>
</div>
</div>
<label for="PMC_No">PMC No:</label><br>
<select id="PMC_No" name="PMC_No" required>
<option value="">Select PMC No</option>
</select><br><br>
<label for="invoice_No">Invoice No:</label><br>
<input type="number" step="0.01" id="invoice_No" name="invoice_No" required><br><br>
<label for="Payment_Amount">Amount:</label><br>
<input type="number" step="0.01" id="Payment_Amount" name="Payment_Amount" required oninput="calculateTDSAndTotal()"><br><br>
<label for="TDS_Percentage">TDS Percentage (%):</label><br>
<input type="number" step="0.01" id="TDS_Percentage" name="TDS_Percentage" oninput="calculateTDSAndTotal()"><br><br>
<label for="TDS_Payment_Amount">TDS Amount:</label><br>
<input type="number" step="0.01" id="TDS_Payment_Amount" name="TDS_Payment_Amount" required readonly><br><br>
<label for="total_amount">Total Amount:</label><br>
<input type="number" step="0.01" id="total_amount" name="total_amount" required readonly><br><br>
<label for="utr">UTR:</label><br>
<input type="text" id="utr" name="utr"><br><br>
<button type="submit">Submit Payment</button>
</form>
</div>
<div id="successPopup" class="success-popup">
<i>&#10004;</i> Payment added successfully!
</div>
<div id="addTable" style="display: none;">
<div class="search-container">
<h2>Payment History</h2>
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
</div>
<table id="sortableTable" border="1">
<thead>
<tr>
<th class="sortable-header">Payment ID</th>
<th class="sortable-header">PMC No</th>
<th>Invoice No</th>
<th>Payment Amount</th>
<th>TDS Amount</th>
<th>Total Amount</th>
<th>UTR</th>
<th>Update</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{% for payment in payments %}
<tr>
<td>{{ payment[0] }}</td>
<td>{{ payment[1] }}</td>
<td>{{ payment[2] }}</td>
<td>{{ payment[3] }}</td>
<td>{{ payment[4] }}</td>
<td>{{ payment[5] }}</td>
<td>{{ payment[6] }}</td>
<td><a href="/edit_payment/{{ payment[0] }}"><img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit" class="icon"></a></td>
<td><a href="/delete_payment/{{ payment[0] }}" onclick="return confirm('Are you sure you want to delete this payment?')"><img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete" class="icon"></a></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<script>
document.getElementById("subcontractor").addEventListener("input", function () {
const query = this.value;
const list = document.getElementById("subcontractor_list");
if (query.length < 2) {
list.innerHTML = '';
return;
}
fetch(`/search_subcontractor?query=${encodeURIComponent(query)}`)
.then(response => response.json())
.then(data => {
list.innerHTML = '';
data.results.forEach(item => {
const div = document.createElement("div");
div.setAttribute("data-id", item.id);
div.textContent = item.name;
list.appendChild(div);
});
});
});
document.getElementById("subcontractor_list").addEventListener("click", function (e) {
const selectedId = e.target.getAttribute("data-id");
const selectedName = e.target.textContent;
if (selectedId) {
document.getElementById("subcontractor_id").value = selectedId;
document.getElementById("subcontractor").value = selectedName;
document.getElementById("subcontractor_list").innerHTML = ""; // hide the list
console.log("Contractor id is", selectedId);
// Fetch PMC numbers
fetch(`/get_pmc_nos_by_subcontractor/${encodeURIComponent(selectedId)}`)
.then(response => response.json())
.then(data => {
console.log("Fetched PMC Nos:", data.pmc_nos);
const pmcDropdown = document.getElementById("PMC_No");
pmcDropdown.innerHTML = "";
const defaultOption = document.createElement("option");
defaultOption.value = "";
defaultOption.textContent = "Select PMC No";
pmcDropdown.appendChild(defaultOption);
data.pmc_nos.forEach(pmc => {
const option = document.createElement("option");
option.value = pmc;
option.textContent = pmc;
pmcDropdown.appendChild(option);
});
if (data.pmc_nos.length === 0) {
alert("No PMC Nos found for this subcontractor.");
}
})
.catch(error => {
console.error("Error fetching PMC Nos:", error);
alert("Failed to fetch PMC numbers.");
});
}
});
</script>
<script>
function calculateTDSAndTotal() {
const amount = parseFloat(document.getElementById("Payment_Amount").value) || 0;
const tdsPercent = parseFloat(document.getElementById("TDS_Percentage").value) || 0;
const tdsAmount = (amount * tdsPercent / 100).toFixed(2);
const totalAmount = (amount - tdsAmount).toFixed(2);
document.getElementById("TDS_Payment_Amount").value = tdsAmount;
document.getElementById("total_amount").value = totalAmount;
}
</script>
<script src="{{ url_for('static', filename='js/showSuccessAlert.js') }}"></script>
</body>
{% endblock %}

69
templates/add_state.html Normal file
View File

@@ -0,0 +1,69 @@
{% extends 'base.html' %}
{% block content %}
<head>
<title>Add State</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/state.js') }}"></script>
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
</head>
<body>
<!-- Button Container to Center Buttons -->
<div class="button-container">
<button id="addButton" class="action-button">Add</button>
<button id="displayButton" class="action-button">Display</button>
</div>
<div id="addForm" style="display: none;">
<h2>Add State</h2>
<form id="stateForm" method="POST">
<label>Enter State :</label>
<input type="text" id="state_Name" name="state_Name" placeholder="State Name" required>
<span id="stateMessage"></span>
<button type="submit" id="submitButton" disabled>Add State</button>
</form>
</div>
<div id="addTable" style="display: none;">
<div class="search-container">
<h2>Display States</h2>
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
</div>
<table id="sortableTable" border="1">
<tr>
<th>State ID</th>
<th class="sortable-header">
State Name
<span class="sort-buttons">
<span class="sort-asc">⬆️</span>
<span class="sort-desc">⬇️</span>
</span>
</th>
<th>Update State</th>
<th>Delete State</th>
</tr>
{% for state in statedata %}
<tr>
<td>{{ state[0] }}</td>
<td>{{ state[1]}}</td>
<td>
<a href="{{ url_for('editState', id=state[0]) }}">
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit"
class="icon">
</a>
</td>
<td>
<a href="{{ url_for('deleteState', id=state[0]) }}"
onclick="return confirm('Are you sure you want to delete this state?')">
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete"
class="icon">
</a>
</td>
</tr>
{% endfor %}
</table>
</div>
</body>
{% endblock %}

View File

@@ -0,0 +1,127 @@
{% extends 'base.html' %}
{% block content %}
<head>
<meta charset="UTF-8">
<title>SubContractor</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/subcontractor.js') }}"></script>
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
</head>
<body>
<!-- Button Container to Center Buttons -->
<div class="button-container">
<button id="addButton" class="action-button">Add</button>
<button id="displayButton" class="action-button">Display</button>
</div>
<div id="addForm" style="display: none;">
<h2>Add Sub-Contractor</h2>
<form name="subcontractorForm" method="POST">
<label>Enter Contractor Name :</label>
<input type="text" id="Contractor_Name" name="Contractor_Name" required onkeyup="validateInput()"><br>
<label>Address :</label>
<!-- <input type="text" name="Address" required>-->
<textarea id="Address" name="Address" required></textarea>
<br>
<label>Mobile No :</label>
<input type="text" id="Mobile_No" name="Mobile_No" required onkeyup="validateInput()" maxlength="10" placeholder="Ex - 9091012011">
<span class="error" id="mobileError" style="color: red;"></span><br>
<label>PAN No :</label>
<input type="text" id="PAN_No" name="PAN_No" required onkeyup="validateInput()" maxlength="10" placeholder="Ex - ABCDE1234F">
<span class="error" id="panError" style="color: red;"></span><br>
<label>Email :</label>
<input type="email" id="Email" name="Email" required onkeyup="validateInput()" placeholder="Ex - user@example.com">
<span class="error" id="emailError" style="color: red;"></span><br>
<label>Gender :</label>
<select name="Gender" required>
<option value="Male">Male</option>
<option value="Female">Female</option>
<option value="Other">Other</option>
</select><br>
<label>GST Registration Type :</label>
<input type="text" name="GST_Registration_Type" required><br>
<label>GST No :</label>
<input type="text" id="GST_No" name="GST_No" placeholder="Ex - 27AAACL5602N1ZE" required ><br>
<label>Generated Password :</label>
<input type="text" id="Contractor_password" name="Contractor_password" >
<span class="error" id="passwordError" style="color: red;"></span><br>
<button type="submit" id="submitBtn" disabled>Submit</button>
</form>
</div>
<div id="addTable" style="display: none;">
<div class="search-container">
<h2>Display SubContractor</h2>
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
</div>
<table id="sortableTable" border="1">
<tr>
<th>Contractor ID</th>
<th class="sortable-header">Contractor Name
<span class="sort-buttons">
<span class="sort-asc">⬆️</span>
<span class="sort-desc">⬇️</span>
</span>
</th>
<th>Address</th>
<th>Mobile No</th>
<th>PAN No</th>
<th>Email</th>
<th>Gender</th>
<th>GST Registration Type</th>
<th class="sortable-header">GST No
<span class="sort-buttons">
<span class="sort-asc">⬆️</span>
<span class="sort-desc">⬇️</span>
</span>
</th>
<th>Update Contractor</th>
<th>Delete Contractor</th>
</tr>
{% for subc in subcontractor %}
<tr>
<td>{{ subc[0] }}</td>
<td>{{ subc[1] }}</td>
<td>{{ subc[2] }}</td>
<td>{{ subc[3] }}</td>
<td>{{ subc[4] }}</td>
<td>{{ subc[5] }}</td>
<td>{{ subc[6] }}</td>
<td>{{ subc[7] }}</td>
<td>{{ subc[8] }}</td>
<td>
<a href="{{ url_for('edit_subcontractor', id=subc[0]) }}">
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit"
class="icon">
</a>
</td>
<td>
<a href="{{ url_for('deleteSubContractor', id=subc[0]) }}"
onclick="return confirm('Are you sure you want to delete?')">
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete"
class="icon">
</a>
</td>
</tr>
{% endfor %}
</table>
</div>
</body>
{% endblock %}

View File

@@ -0,0 +1,99 @@
{% extends 'base.html' %}
{% block content %}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Village Management</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/village.js') }}"></script>
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
</head>
<body>
<!-- Button Container to Center Buttons -->
<div class="button-container">
<button id="addButton" class="action-button">Add</button>
<button id="displayButton" class="action-button">Display</button>
</div>
<div id="addForm" style="display: none;">
<div class="container">
<div class="form-block">
<h2>Add a New Village</h2>
<form id="villageForm" method="POST">
<label for="state_Id">State:</label>
<select id="state_Id" name="state_Id" required>
<option value="" disabled selected>Select State</option>
{% for state in states %}
<option value="{{ state[0] }}">{{ state[1] }}</option>
{% endfor %}
</select>
<label for="district_Id">District:</label>
<select id="district_Id" name="district_Id" required disabled>
<option value="" disabled selected>Select District</option>
</select>
<label for="block_Id">Block:</label>
<select id="block_Id" name="block_Id" required disabled>
<option value="" disabled selected>Select Block</option>
</select>
<label for="Village_Name">Village Name:</label>
<input type="text" id="Village_Name" name="Village_Name" placeholder="Enter Village Name" required>
<span id="villageMessage"></span>
<button type="submit" id="submitVillage" disabled>Add Village</button>
</form>
</div>
</div>
</div>
<div id="addTable" style="display: none;">
<div class="search-container">
<h2>Display Villages</h2>
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
</div>
<table id="sortableTable" border="1">
<tr>
<th>Village Sr No</th>
<th class="sortable-header">
Village Name
<span class="sort-buttons">
<span class="sort-asc">⬆️</span>
<span class="sort-desc">⬇️</span>
</span></th>
<th class="sortable-header">Block Name
<span class="sort-buttons">
<span class="sort-asc">⬆️</span>
<span class="sort-desc">⬇️</span>
</span></th>
<th>Update</th>
<th>Delete</th>
</tr>
{% for village in villages %}
<tr>
<td>{{ village[0] }}</td>
<td>{{ village[1] }}</td>
<td>{{ village[2] }}</td>
<td>
<a href="{{ url_for('edit_village', village_id=village[0]) }}">
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit"
class="icon">
</a>
</td>
<td>
<a href="{{ url_for('delete_village', village_id=village[0]) }}"
onclick="return confirm('Are you sure you want to delete this village?');">
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete"
class="icon">
</a>
</td>
</tr>
{% endfor %}
</table>
</div>
</body>
{% endblock %}

View File

@@ -0,0 +1,49 @@
{% extends 'base.html' %}
{% block content %}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Profile</title>
</head>
<body>
<div class="container">
<h2>Admin Profile</h2>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<p class="{{ category }}">{{ message }}</p>
{% endfor %}
{% endif %}
{% endwith %}
<form action="{{ url_for('admin_profile') }}" method="POST" enctype="multipart/form-data">
<div class="profile-picture">
<!-- <img id="profile-pic-preview" src="{{ url_for('static', filename='images/' + (profile['profile_picture'] or 'default.png')) }}" alt="Profile Picture" />-->
<input type="file" name="profile_picture" id="profile-pic-input" onchange="previewImage()">
</div>
<label>Username:</label>
<input type="text" name="username" value="{{ profile['user_name'] }}" required>
<label>Phone:</label>
<input type="tel" name="phone" value="{{ profile['mobile'] }}" required>
<label>Email:</label>
<input type="email" name="email" value="{{ profile['email'] }}" required>
<label>New Password:</label>
<input type="password" name="new_password">
<label>Current Password (required for password change):</label>
<input type="password" name="current_password">
<button type="submit">Save Changes</button>
</form>
</div>
<script>
function previewImage() {
const file = document.getElementById('profile-pic-input').files[0];
const reader = new FileReader();
reader.onload = function(e) {
document.getElementById('profile-pic-preview').src = e.target.result;
};
if (file) {
reader.readAsDataURL(file);
}
}
</script>
</body>
{% endblock %}

97
templates/base.html Normal file
View File

@@ -0,0 +1,97 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{% block title %}Payment Reconciliation{% endblock %}</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/base.css') }}">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<!-- Sidebar Toggle Button -->
<button class="menu-icon" onclick="toggleSidebar()">
<i class="fa-solid fa-bars"></i>
</button>
<!-- Sidebar -->
<div class="sidebar" id="sidebar">
<ul class="nav-menu">
<li class="nav-item">
<a href="/" class="nav-link active">
<i class="fas fa-home"></i> Dashboard
</a>
</li>
<li class="nav-item">
<a href="/upload_excel_file" class="nav-link">
<i class="fas fa-book"></i> Import Excel
</a>
</li>
<li class="nav-item">
<a href="/report" class="nav-link">
<i class="fas fa-cog"></i> Report
</a>
</li>
<li class="card">
<a href="/add_state" class="nav-link">
<i class="fas fa-arrow-right"></i> State
</a>
</li>
<li class="card">
<a href="/add_district" class="nav-link">
<i class="fas fa-arrow-right"></i> District
</a>
</li>
<li class="card">
<a href="/add_block" class="nav-link">
<i class="fas fa-arrow-right"></i> Blocks
</a>
</li>
<li class="card">
<a href="/add_village" class="nav-link">
<i class="fas fa-arrow-right"></i> village
</a>
</li>
<li class="card">
<a href="/subcontractor" class="nav-link">
<i class="fas fa-arrow-right"></i> Sub-Contractor
</a>
</li>
<li class="card">
<a href="/add_invoice" class="nav-link">
<i class="fas fa-arrow-right"></i> Invoice
</a>
</li>
<li class="card">
<a href="/add_payment" class="nav-link">
<i class="fas fa-arrow-right"></i> Payment
</a>
</li>
<li class="card">
<a href="/add_gst_release" class="nav-link">
<i class="fas fa-arrow-right"></i> GST Release
</a>
</li>
<li class="card">
<a href="/add_hold_type" class="nav-link">
<i class="fas fa-arrow-right"></i> Hold Types
</a>
</li>
</ul>
</div>
<!-- Main Content -->
<div class="content" id="content">
{% block content %}{% endblock %}
</div>
<!-- Sidebar Toggle Script -->
<script>
function toggleSidebar() {
document.getElementById("sidebar").classList.toggle("open");
document.getElementById("content").classList.toggle("shift");
}
</script>
</body>
</html>

60
templates/edit_block.html Normal file
View File

@@ -0,0 +1,60 @@
{% extends 'base.html' %}
{% block content %}
<head>
<title>Edit Block</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
<script>
window.onload = function () {
const flash = document.getElementById('flash-message');
if (flash) {
alert(flash.innerText);
}
}
</script>
</head>
<body>
<h2>Edit Block</h2>
<!-- Flash Message -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div id="flash-message" style="display:none;" data-category="{{ category }}">{{ message }}</div>
{% endfor %}
{% endif %}
{% endwith %}
<!-- Edit Block Form -->
<form method="POST">
<label for="state_Id">State:</label>
<select name="state_Id" id="state_Id" required>
<option value="" disabled>Select State</option>
{% for state in states %}
<option value="{{ state[0] }}" {% if state[0] == block_data[1] %} selected {% endif %}>
{{ state[1] }}
</option>
{% endfor %}
</select><br><br>
<label for="district_Id">District:</label>
<select name="district_Id" id="district_Id" required>
<option value="" disabled>Select District</option>
{% for district in districts %}
<option value="{{ district[0] }}" {% if district[0] == block_data[1] %} selected {% endif %}>
{{ district[1] }}
</option>
{% endfor %}
</select><br><br>
<label for="block_Name">Block Name:</label>
<input type="text" name="block_Name" value="{{ block_data[0] }}" placeholder="Enter Block Name" required><br><br>
<button type="submit">Update Block</button>
</form>
</body>
{% endblock %}

View File

@@ -0,0 +1,26 @@
{% extends 'base.html' %}
{% block content %}
<head>
<title>Edit District</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<h2>Edit District</h2>
<form method="POST">
<label for="state_Id">State :</label>
<select name="state_Id" required>
<option value="" disabled>Select State</option>
{% for state in states %}
<option value="{{ state[0] }}" {% if state[0] == districtdata[1] %}selected{% endif %}>{{ state[1] }}</option>
{% endfor %}
</select>
<label>Enter District :</label>
<input type="text" name="district_Name" placeholder="District Name" value="{{ districtdata[0] }}" required>
<button type="submit">Update District</button>
</form>
</body>
{% endblock %}

View File

@@ -0,0 +1,37 @@
{% extends 'base.html' %}
{% block content %}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Edit GST Release</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<h2>Edit GST Release</h2>
<form action="/edit_gst_release/{{ gst_release_data[0] }}" method="POST">
<!-- <label for="invoice_id">Invoice Id:</label><br>-->
<!-- <input type="number" id="invoice_id" name="invoice_id" value="{{ gst_release_data[0] }}" required><br><br>-->
<label for="PMC_No">PMC No :</label><br>
<input type="number" id="PMC_No" name="PMC_No" value="{{ gst_release_data[1] }}" required><br><br>
<label for="invoice_No">Invoice No:</label><br>
<input type="number" step="0.01" id="invoice_No" name="invoice_No" value="{{ gst_release_data[2] }}"
required><br><br>
<label for="basic_amount">Amount:</label><br>
<input type="number" step="0.01" id="basic_amount" name="basic_amount" value="{{ gst_release_data[3] }}"
required><br><br>
<label for="final_amount">Total Amount:</label><br>
<input type="number" step="0.01" id="final_amount" name="final_amount" value="{{ gst_release_data[4] }}"
required><br><br>
<button type="submit">Update GST Release</button>
</form>
</body>
{% endblock %}

View File

@@ -0,0 +1,62 @@
{% extends 'base.html' %}
{% block content %}
<head>
<title>Edit Hold Type</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<h2>Edit Hold Type</h2>
<form id="updateHoldTypeForm">
<input type="hidden" id="hold_type_id" value="{{ hold_type[0] }}">
<label for="edit_hold_type">Hold Type:</label>
<input type="text" id="edit_hold_type" name="hold_type" value="{{ hold_type[1] }}" required>
<button type="submit">Update</button>
<a href="{{ url_for('add_hold_type') }}"></a>
</form>
</body>
<script>
$(document).ready(function () {
$('#updateHoldTypeForm').submit(function (e) {
e.preventDefault();
const holdTypeId = $('#hold_type_id').val();
const newHoldType = $('#edit_hold_type').val().trim();
if (!/^[A-Za-z]/.test(newHoldType)) {
alert('Hold Type must start with a letter.');
return;
}
// Create a FormData object to properly submit form data
const formData = new FormData();
formData.append('hold_type', newHoldType);
$.ajax({
url: '/update_hold_type/' + holdTypeId,
method: 'POST',
data: formData,
processData: false,
contentType: false,
success: function () {
// The server will redirect, so we don't need to handle the response here
window.location.href = "{{ url_for('add_hold_type') }}";
},
error: function (xhr) {
const errMsg = xhr.responseJSON?.message || 'Failed to update Hold Type';
alert('Error: ' + errMsg);
}
});
});
});
</script>
{% endblock %}

207
templates/edit_invoice.html Normal file
View File

@@ -0,0 +1,207 @@
{% extends 'base.html' %}
{% block content %}
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Edit Invoice</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/invoice.css') }}">
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style1.css') }}">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<div id="editForm">
<h2>Edit Invoice</h2>
<!-- Success Alert Box -->
<div id="invoiceSuccessAlert" class="success-alert" style="display:none;">
Invoice successfully updated!
</div>
<form id="invoiceForm" action="{{ url_for('edit_invoice', invoice_id=invoice.Invoice_Id) }}" method="POST">
<!-- Subcontractor Field -->
<div class="row1">
<div>
<label for="subcontractor">Subcontractor Name:</label>
<input class="form-control" list="subcontractor_list" id="subcontractor" name="subcontractor"
value="{{ invoice.Contractor_Name }}" placeholder="Type to search..." required>
<input type="hidden" id="subcontractor_id" name="subcontractor_id" value="{{ invoice.Subcontractor_Id }}">
<datalist id="subcontractor_list"></datalist>
</div>
</div>
<!-- Village and PMC No Fields -->
<div class="row2">
<div>
<label for="village">Village Name:</label>
<input type="text" id="village" name="village" value="{{ invoice.Village_Name }}" required/>
<datalist id="village_list"></datalist>
</div>
<div>
<label for="pmc_no">PMC No:</label>
<input type="text" id="pmc_no" name="pmc_no" value="{{ invoice.PMC_No }}" required/>
</div>
</div>
<!-- Work Type and Invoice Details -->
<div class="row2">
<div>
<label for="work_type">Work Type:</label>
<input type="text" id="work_type" name="work_type" value="{{ invoice.Work_Type }}" required/>
</div>
<div>
<label for="invoice_details">Invoice Details:</label>
<textarea id="invoice_details" name="invoice_details" required>{{ invoice.Invoice_Details }}</textarea>
</div>
</div>
<!-- Invoice No and Invoice Date -->
<div class="row2">
<div>
<label for="invoice_no">Invoice No:</label>
<input type="text" id="invoice_no" name="invoice_no" value="{{ invoice.Invoice_No }}" required/>
</div>
<div>
<label for="invoice_date">Invoice Date:</label>
<input type="date" id="invoice_date" name="invoice_date" value="{{ invoice.Invoice_Date }}" required/>
</div>
</div>
<!-- Amount Fields -->
<div class="row3">
<div>
<label for="basic_amount">Basic Amount:</label>
<input type="number" step="0.01" id="basic_amount" name="basic_amount" value="{{ invoice.Basic_Amount }}" required/>
</div>
<div>
<label for="debit_amount">Debit Amount:</label>
<input type="number" step="0.01" id="debit_amount" name="debit_amount" value="{{ invoice.Debit_Amount }}" required/>
</div>
<div>
<label for="after_debit_amount">After Debit Amount:</label>
<input type="number" step="0.01" id="after_debit_amount" name="after_debit_amount" value="{{ invoice.After_Debit_Amount }}" required/>
</div>
</div>
<!-- GST, TDS, and Other Amounts -->
<div class="row3">
<div>
<label for="amount">Amount:</label>
<input type="number" step="0.01" id="amount" name="amount" value="{{ invoice.Amount }}" required/>
</div>
<div>
<label for="gst_amount">GST Amount:</label>
<input type="number" step="0.01" id="gst_amount" name="gst_amount" value="{{ invoice.GST_Amount }}" required/>
</div>
<div>
<label for="tds_amount">TDS Amount:</label>
<input type="number" step="0.01" id="tds_amount" name="tds_amount" value="{{ invoice.TDS_Amount }}" required/>
</div>
</div>
<!-- SD, On Commission, Hydro Testing -->
<div class="row3">
<div>
<label for="sd_amount">SD Amount:</label>
<input type="number" step="0.01" id="sd_amount" name="sd_amount" value="{{ invoice.SD_Amount }}" required/>
</div>
<div>
<label for="on_commission">On Commission:</label>
<input type="number" step="0.01" id="on_commission" name="on_commission" value="{{ invoice.On_Commission }}" required/>
</div>
<div>
<label for="hydro_testing">Hydro Testing:</label>
<input type="number" step="0.01" id="hydro_testing" name="hydro_testing" value="{{ invoice.Hydro_Testing }}" required/>
</div>
</div>
<!-- Hold Amount Section -->
<div id="hold_amount_container">
{% set seen_types = [] %}
{% for hold in invoice.hold_amounts %}
{% if hold.hold_type not in seen_types %}
{% set _ = seen_types.append(hold.hold_type) %}
<div class="hold-amount-row">
<label for="hold_type_{{ loop.index }}">Hold Type:</label>
<input type="text" id="hold_type_{{ loop.index }}" name="hold_type[]" value="{{ hold.hold_type }}" required/>
<label for="hold_amount_{{ loop.index }}">Hold Amount:</label>
<input type="number" step="0.01" id="hold_amount_{{ loop.index }}" name="hold_amount[]" value="{{ hold.hold_amount }}" required/>
<button type="button" class="remove-hold-amount">Remove</button>
</div>
{% endif %}
{% endfor %}
</div>
<div class="hold-row">
<button type="button" id="add_hold_amount" class="button">+ Add Hold Amount</button>
</div>
<!-- Final Amounts -->
<div class="row2">
<div>
<label for="gst_sd_amount">GST SD Amount:</label>
<input type="number" step="0.01" id="gst_sd_amount" name="gst_sd_amount" value="{{ invoice.GST_SD_Amount }}" required/>
</div>
<div>
<label for="final_amount">Final Amount:</label>
<input type="number" step="0.01" id="final_amount" name="final_amount" value="{{ invoice.Final_Amount }}" required/>
</div>
</div>
<!-- Submit Button -->
<button type="submit" class="button">Update</button>
</form>
</div>
<!-- JS for dynamic hold amount rows -->
<script>
$(document).ready(function() {
// Add new hold amount row
$("#add_hold_amount").click(function() {
const index = $("#hold_amount_container .hold-amount-row").length;
const newRow = `
<div class="hold-amount-row">
<label for="hold_type_${index}">Hold Type:</label>
<input type="text" id="hold_type_${index}" name="hold_type[]" required/>
<label for="hold_amount_${index}">Hold Amount:</label>
<input type="number" step="0.01" id="hold_amount_${index}" name="hold_amount[]" required/>
<button type="button" class="remove-hold-amount">Remove</button>
</div>
`;
$("#hold_amount_container").append(newRow);
});
// Remove hold amount row
$(document).on("click", ".remove-hold-amount", function() {
$(this).closest(".hold-amount-row").remove();
});
// Submit form via AJAX
$("#invoiceForm").submit(function(e) {
e.preventDefault();
$.ajax({
type: "POST",
url: $(this).attr("action"),
data: $(this).serialize(),
success: function(response) {
if(response.status === "success") {
$("#invoiceSuccessAlert").fadeIn().delay(3000).fadeOut();
alert("Invoice updated successfully!"); // <-- Popup alert
}
},
error: function(xhr) {
alert("Error: " + xhr.responseJSON.message);
}
});
});
});
</script>
</body>
{% endblock %}

View File

@@ -0,0 +1,49 @@
{% extends 'base.html' %}
{% block content %}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Edit Payment</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<h2>Edit Payment</h2>
<form action="/edit_payment/{{ payment_data[0] }}" method="POST">
<!-- <label for="invoice_id">Invoice ID:</label><br>-->
<!-- <select id="invoice_id" name="invoice_id" required>-->
<!-- {% for invoice in invoices %}-->
<!-- <option value="{{ invoice[0] }}" {% if invoice[0] == payment_data[0] %}selected{% endif %}>-->
<!-- {{ invoice[1] }}-->
<!-- </option>-->
<!-- {% endfor %}-->
<!-- </select><br><br>-->
<label for="PMC_No">PMC No:</label><br>
<input type="number" step="0.01" id="PMC_No" name="PMC_No" value="{{ payment_data[1] }}" required><br><br>
<label for="invoice_No">Invoice No:</label><br>
<input type="number" step="0.01" id="invoice_No" name="invoice_No" value="{{ payment_data[2] }}" required><br><br>
<label for="Payment_Amount">Amount:</label><br>
<input type="number" step="0.01" id="Payment_Amount" name="Payment_Amount" value="{{ payment_data[3] }}"
required><br><br>
<label for="TDS_Payment_Amount">TDS Amount:</label><br>
<input type="number" step="0.01" id="TDS_Payment_Amount" name="TDS_Payment_Amount" value="{{ payment_data[4] }}"
required><br><br>
<label for="total_amount">Total Amount:</label><br>
<input type="number" step="0.01" id="total_amount" name="total_amount" value="{{ payment_data[5] }}"
required><br><br>
<label for="utr">UTR:</label><br>
<input type="text" id="utr" name="utr" value="{{ payment_data[6] }}"><br><br>
<button type="submit">Update Payment</button>
</form>
</body>
{% endblock %}

17
templates/edit_state.html Normal file
View File

@@ -0,0 +1,17 @@
{% extends 'base.html' %}
{% block content %}
<head>
<title>Edit State</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<h2>Edit State</h2>
<form method="POST">
<input type="text" name="state_Name" placeholder="State Name" value="{{ state[1] }}" required>
<button type="submit">Update</button>
</form>
</body>
{% endblock %}

View File

@@ -0,0 +1,50 @@
{% extends 'base.html' %}
{% block content %}
<head>
<meta charset="UTF-8">
<title>Edit SubContractor</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<h2>Edit Sub-Contractor</h2>
<form method="POST">
<input type="hidden" name="Contractor_Id" value="{{ subcontractor[0] }}">
<label>Enter Contractor Name :</label>
<input type="text" name="Contractor_Name" value="{{ subcontractor[1] }}" required><br>
<label>Address :</label>
<input type="text" name="Address" value="{{ subcontractor[2] }}" required><br>
<label>Mobile No :</label>
<input type="text" name="Mobile_No" value="{{ subcontractor[3] }}" required><br>
<label>PAN No :</label>
<input type="text" name="PAN_No" value="{{ subcontractor[4] }}" required><br>
<label>Email :</label>
<input type="email" name="Email" value="{{ subcontractor[5] }}" required><br>
<label>Gender :</label>
<select name="Gender" required>
<option value="Male" {% if subcontractor[6]=='Male' %}selected{% endif %}>Male</option>
<option value="Female" {% if subcontractor[6]=='Female' %}selected{% endif %}>Female</option>
<option value="Other" {% if subcontractor[6]=='Other' %}selected{% endif %}>Other</option>
</select><br>
<label>GST Registration Type :</label>
<input type="text" name="GST_Registration_Type" value="{{ subcontractor[7] }}" required><br>
<label>GST No :</label>
<input type="text" name="GST_No" value="{{ subcontractor[8] }}" required><br>
<label>Enter New Password :</label>
<input type="text" name="Contractor_password" value="{{ subcontractor[9] }}" required><br>
<button type="submit">Update</button>
</form>
</body>
{% endblock %}

View File

@@ -0,0 +1,52 @@
{% extends 'base.html' %}
{% block content %}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Edit Village</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<div class="container">
<div class="form-block">
<h2>Edit Village</h2>
<form id="editVillageForm" method="POST">
<label for="block_Id">Select Block:</label>
<select id="block_Id" name="block_Id" required>
<option value="" disabled>Select Block</option>
{% for block in blocks %}
<option value="{{ block[0] }}" {% if block[0] == village_data[1] %}selected{% endif %}>
{{ block[1] }}
</option>
{% endfor %}
</select>
<label for="Village_Name">Enter Village Name:</label>
<input type="text" id="Village_Name" name="Village_Name" value="{{ village_data[0] }}" required>
<span id="villageMessage"></span>
<button type="submit">Update Village</button>
</form>
</div>
<!-- Flash Message (Hidden, used for JS popup) -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div id="flash-message" data-category="{{ category }}" style="display:none;">{{ message }}</div>
{% endfor %}
{% endif %}
{% endwith %}
</div>
<script>
window.onload = function () {
const flash = document.getElementById('flash-message');
if (flash && flash.innerText.trim() !== "") {
alert(flash.innerText);
}
};
</script>
</body>
{% endblock %}

105
templates/index.html Normal file
View File

@@ -0,0 +1,105 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Payment Reconciliation </title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/index.css') }}">
</head>
<body>
<div class="sidebar">
<img src="https://lceplpmprod.btltech.xyz/assets/images/lcpl.png" alt="logo-image" class="logo">
<ul class="nav-menu">
<li class="nav-item">
<a href="#" class="nav-link active">
<i class="fas fa-home"></i> Dashboard
</a>
</li>
<li class="nav-item">
<a href="/upload_excel_file" class="nav-link">
<i class="fas fa-book"></i> Import Excel
</a>
</li>
<li class="nav-item">
<a href="/report" class="nav-link">
<i class="fas fa-cog"></i> Report Details
</a>
</li>
</ul>
<div class="user-section">
<img src="{{ url_for('static', filename='images/icons/male_profile.jpg') }}" alt="User Avatar">
<div class="user-info">
<span>admin</span>
</div>
</div>
</div>
<div class="company-info">
<marquee behavior="scroll" direction="left">
<h2 class="company-name">Laxmi Civil Engineering Services Pvt. Ltd.</h2>
</marquee>
<p class="app-name">Payment Reconciliation</p>
</div>
<div class="content">
<div class="menu">
<div class="card">
<h2>Profile</h2>
<a class="btn" href="#">Go ➜</a>
</div>
<div class="card">
<h2>States</h2>
<a class="btn" href="/add_state">Go ➜</a>
</div>
<div class="card">
<h2>District</h2>
<a class="btn" href="/add_district">Go ➜</a>
</div>
<div class="card">
<h2>Blocks</h2>
<a class="btn" href="/add_block">Go ➜</a>
</div>
<div class="card">
<h2>Village</h2>
<a class="btn" href="/add_village">Go ➜</a>
</div>
<div class="card">
<h2>Sub-Contractor</h2>
<a class="btn" href="/subcontractor">Go ➜</a>
</div>
<div class="card">
<h2>Invoice</h2>
<a class="btn" href="/add_invoice">Go ➜</a>
</div>
<div class="card">
<h2>Payment</h2>
<a class="btn" href="/add_payment">Go ➜</a>
</div>
<div class="card">
<h2>GST Release</h2>
<a class="btn" href="/add_gst_release">Go ➜</a>
</div>
<div class="card">
<h2>Hold Types</h2>
<a class="btn" href="/add_hold_type">Go ➜</a>
</div>
<div class="card">
<h2>Hold Release Types</h2>
<a class="btn" href="/add_hold_release">Go ➜</a>
</div>
</div>
</div>
</body>
</html>

340
templates/pmc_report.html Normal file
View File

@@ -0,0 +1,340 @@
{% extends 'base.html' %}
{% block content %}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PMC Report</title>
<!-- <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">-->
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/subcontractor_report.css') }}">
</head>
<body>
<div class="container">
<h2>PMC Report</h2>
<div class="info">
<h2>Contractor Details</h2>
<div class="row2">
<div>
<label for="subcontractor">Subcontractor Name:</label>
<input type="text" id="subcontractor" name="subcontractor" value="{{ info.Contractor_Name }}"
readonly/>
</div>
<div>
<label for="Address">Address :</label>
<textarea id="Address" name="Address" readonly>{{ info.Address }}</textarea>
</div>
</div>
<div class="row3">
<div>
<label for="PAN_No">PAN No :</label>
<input type="text" id="PAN_No" name="PAN_No" value="{{ info.PAN_No }}" readonly/>
</div>
<div>
<label for="Mobile_No">Mobile Number :</label>
<input type="text" id="Mobile_No" name="Mobile_No" value="{{ info.Mobile_No }}" readonly/>
</div>
<div>
<label for="Email">Email :</label>
<input type="text" id="Email" name="Email" value="{{ info.Email }}" readonly/>
</div>
</div>
<div class="row2">
<div>
<label for="GST_Registration_Type">GST Registration Type :</label>
<input type="text" id="GST_Registration_Type" name="GST_Registration_Type"
value="{{ info.GST_Registration_Type }}" readonly/>
</div>
<div>
<label for="GST_No">GST No:</label>
<input type="text" id="GST_No" name="GST_No" value="{{ info.GST_No }}" readonly/>
</div>
</div>
<h2>PMC Report for PMC No: {{ info.PMC_No}}</h2>
<div class="row3">
<div>
<label for="State">State :</label>
<input type="text" id="State" name="State" value="{{ info.State_Name }}" readonly/>
</div>
<div>
<label for="District">District :</label>
<input type="text" id="District" name="District" value="{{ info.District_Name }}" readonly/>
</div>
<div>
<label for="Block">Block :</label>
<input type="text" id="Block" name="Block" value="{{ info.Block_Name }}" readonly/>
</div>
</div>
<div class="row2">
<div>
<label for="PMC_No">PMC No:</label>
<input type="text" id="PMC_No" name="PMC_No" value="{{ info.PMC_No }}" readonly/>
</div>
<div>
<label for="Village_Name">Village Name :</label>
<input type="text" id="Village_Name" name="Village_Name"
value="{{ info.Village_Name.capitalize() }}" readonly/>
</div>
</div>
</div>
</div>
<h3>Invoice Details</h3>
<table>
<thead>
<tr>
<th>PMC No</th>
<th>Village Name</th>
<th>Work Type</th>
<th>Invoice Details</th>
<th>Invoice Date</th>
<th>Invoice No</th>
<th>Basic Amount</th>
<th>Debit</th>
<th>After Debit Amt</th>
<th>GST (18%)</th>
<th>Amount</th>
<th>TDS (1%)</th>
<th>SD (5%)</th>
<th>On Commission</th>
<th>Hydro Testing</th>
<!-- Dynamic Hold Types -->
{% set hold_types = invoices | map(attribute='hold_type') | reject('none') | unique | list %}
{% for hold in hold_types %}
<th>{{ hold }}</th>
{% endfor %}
<th>GST SD (18%)</th>
<th>Final Amount</th>
</tr>
</thead>
<tbody>
{% if invoices %}
{% for invoice in invoices %}
<tr>
<td>{{ invoice.PMC_No }}</td>
<td>{{ invoice.Village_Name.capitalize() }}</td>
<td>{{ invoice.Work_Type }}</td>
<td>{{ invoice.Invoice_Details }}</td>
<td>{{ invoice.Invoice_Date }}</td>
<td>{{ invoice.Invoice_No }}</td>
<td>{{ invoice.Basic_Amount }}</td>
<td>{{ invoice.Debit_Amount }}</td>
<td>{{ invoice.After_Debit_Amount }}</td>
<td>{{ invoice.GST_Amount }}</td>
<td>{{ invoice.Amount }}</td>
<td>{{ invoice.TDS_Amount }}</td>
<td>{{ invoice.SD_Amount }}</td>
<td>{{ invoice.On_Commission }}</td>
<td>{{ invoice.Hydro_Testing }}</td>
<!-- Dynamic Hold Amounts -->
{% for hold in hold_types %}
<td>
{% if invoice.hold_type == hold %}
{{ invoice.hold_amount }}
{% else %}
0
{% endif %}
</td>
{% endfor %}
<td>{{ invoice.GST_SD_Amount }}</td>
<td>{{ invoice.Final_Amount }}</td>
</tr>
{% endfor %}
<tr>
<th colspan="6">Total</th>
<th>{{total["sum_invo_basic_amt"]}}</th>
<th>{{total["sum_invo_debit_amt"]}}</th>
<th>{{total["sum_invo_after_debit_amt"]}}</th>
<th>{{total["sum_invo_gst_amt"]}}</th>
<th>{{total["sum_invo_amt"]}}</th>
<th>{{total["sum_invo_tds_amt"]}}</th>
<th>{{total["sum_invo_ds_amt"]}}</th>
<th>{{total["sum_invo_on_commission"]}}</th>
<th>{{total["sum_invo_hydro_test"]}}</th>
{% set hold_types = invoices | map(attribute='hold_type') | unique | list %}
{% for hold in hold_types %}
<th>{{total["sum_invo_hold_amt"]}}</th>
{% endfor %}
<th>{{total["sum_invo_gst_sd_amt"]}}</th>
<th>{{total["sum_invo_final_amt"]}}</th>
</tr>
{% else %}
<tr>
<td colspan="{{ 17 + hold_types|length }}">No invoices found.</td>
</tr>
{% endif %}
</tbody>
</table>
<h3>Hold Release</h3>
<table>
<thead>
<tr>
<th>PMC No</th>
<th>Invoice No</th>
<th>Invoice Details</th>
<th>Basic Amount</th>
<th>Total Amount</th>
<th>UTR</th>
</tr>
</thead>
<tbody>
{%if hold_release%}
{%for hold in hold_release%}
<tr>
<td>{{ hold['PMC_No'] }}</td>
<td>{{ hold['Invoice_No'] }}</td>
<td>{{ hold['Invoice_Details'] }}</td>
<td>{{ hold['Basic_Amount'] }}</td>
<td>{{ hold['Total_Amount'] }}</td>
<td>{{ hold['UTR'] }}</td>
</tr>
{%endfor%}
{%else%}
<tr>
<td colspan="6" style="text-align:center;">No data present</td>
</tr>
{%endif%}
</tbody>
</table>
<br>
<h3>GST Release Note Details</h3>
<table>
<thead>
<tr>
<th>PMC No</th>
<th>Invoice No</th>
<th>Basic Amount</th>
<th>Final Amount</th>
</tr>
</thead>
<tbody>
{% if gst_rel %}
{% for gst in gst_rel %}
<tr>
<td>{{ gst.pmc_no }}</td>
<td>{{ gst.invoice_no }}</td>
<td>{{ gst.basic_amount }}</td>
<td>{{ gst.final_amount }}</td>
</tr>
{% endfor %}
<tr>
<th colspan="2">Total</th>
<th>{{total["sum_gst_basic_amt"]}}</th>
<th>{{total["sum_gst_final_amt"]}}</th>
</tr>
{% else %}
<tr>
<td colspan="4">No GST release found.</td>
</tr>
{% endif %}
</tbody>
</table>
<tr>
<h3>Credit Details</h3>
</tr>
<table>
<thead>
<tr>
<th>PMC No</th>
<th>Invoice Details</th>
<th>Basic Amount</th>
<th>Debit</th>
<th>After Debit Amt</th>
<th>GST Amount</th>
<th>Amount</th>
<th>Final Amount</th>
<th>Payment Amount</th>
<th>Total Amount</th>
<th>UTR</th>
</tr>
{% if credit_note %}
{% for credit in credit_note %}
<tr>
<td>{{ credit["PMC_No"] }}</td>
<td>{{ credit["Invoice_Details"] }}</td>
<td>{{ credit["Basic_Amount"] }}</td>
<td>{{ credit["Debit_Amount"] }}</td>
<td>{{ credit["After_Debit_Amount"] }}</td>
<td>{{ credit["GST_Amount"] }}</td>
<td>{{ credit["Amount"] }}</td>
<td>{{ credit["Final_Amount"] }}</td>
<td>{{ credit["Payment_Amount"] }}</td>
<td>{{ credit["Total_Amount"] }}</td>
<td>{{ credit["UTR"] }}</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="11">No Credit note found.</td>
</tr>
{% endif %}
</thead>
</table>
<br>
<h3>Payment Details</h3>
<table>
<thead>
<tr>
<th>PMC No</th>
<th>Invoice No</th>
<th>Amount</th>
<th>TDS Amount @ 1% on BASIC AMOUNT</th>
<th>Total Amount Paid</th>
<th>UTR</th>
</tr>
</thead>
<tbody>
{% if payments %}
{% for pay in payments %}
<tr>
<td>{{ pay.pmc_no }}</td>
<td>{{ pay.invoice_no }}</td>
<td>{{ pay.Payment_Amount }}</td>
<td>{{ pay.TDS_Payment_Amount }}</td>
<td>{{ pay.Total_amount }}</td>
<td>{{ pay.utr}}</td>
</tr>
{% endfor %}
<tr>
<th colspan="2">Total</th>
<th>{{total["sum_pay_payment_amt"]}}</th>
<th>{{total["sum_pay_tds_payment_amt"]}}</th>
<th>{{total["sum_pay_total_amt"]}}</th>
<th></th>
</tr>
{% else %}
<tr>
<td colspan="6">No payment found.</td>
</tr>
{% endif %}
</tbody>
</table>
<a href="/download_pmc_report/{{ info.PMC_No}}">
<button class="download-btn">Download PMC Report</button>
</a>
</body>
{% endblock %}

108
templates/report.html Normal file
View File

@@ -0,0 +1,108 @@
{% extends 'base.html' %}
{% block content %}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Contractor Search</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/report.css') }}">
<script src="{{ url_for('static', filename='js/searchContractor.js') }}"></script>
</head>
<body>
<div id="report" class="page">
<h2>Search Contractor Report</h2>
<div>
<form id="search-form">
<div class="row2">
<div>
<label for="subcontractor_name">Subcontractor Name:</label>
<input type="text" id="subcontractor_name" name="subcontractor_name">
</div>
<div>
<label for="pmc_no">PMC No:</label>
<input type="text" id="pmc_no" name="pmc_no">
</div>
</div>
<div class="row2">
<div>
<label for="state">State:</label>
<input type="text" id="state" name="state">
</div>
<div>
<label for="district">District:</label>
<input type="text" id="district" name="district">
</div>
</div>
<div class="row2">
<div>
<label for="block">Block:</label>
<input type="text" id="block" name="block">
</div>
<div>
<label for="village">Village:</label>
<input type="text" id="village" name="village">
</div>
</div>
<div class="row2">
<div>
<label for="year_from">Year From:</label>
<input type="date" id="year_from" name="year_from">
</div>
<div>
<label for="year_to">Year To:</label>
<input type="date" id="year_to" name="year_to">
</div>
</div>
</form>
<h2>Contractor List</h2>
<table border="1" id="result-table">
<thead>
<tr>
<th class="sortable">Contractor Name
<select>
<option value="">🔽</option>
<option value="asc">Ascending</option>
<option value="desc">Descending</option>
</select>
</th>
<th>PMC No</th>
<th class="sortable">State
<select>
<option value="">🔽</option>
<option value="asc">Ascending</option>
<option value="desc">Descending</option>
</select>
</th>
<th class="sortable">District
<select>
<option value="">🔽</option>
<option value="asc">Ascending</option>
<option value="desc">Descending</option>
</select>
</th>
<th class="sortable">Block
<select>
<option value="">🔽</option>
<option value="asc">Ascending</option>
<option value="desc">Descending</option>
</select>
</th>
<th class="sortable">Village
<select>
<option value="">🔽</option>
<option value="asc">Ascending</option>
<option value="desc">Descending</option>
</select>
</th>
</tr>
</thead>
<tbody>
<!-- Results will be dynamically populated -->
</tbody>
</table>
</div>
</div>
</body>
{% endblock %}

View File

@@ -0,0 +1,85 @@
<!DOCTYPE html>
<html>
<head>
<title>Excel Data</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/show_excel.css') }}">
<!-- <script src="{{ url_for('static', filename='js/save_excel_file.js') }}"></script>-->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script src="{{ url_for('static', filename='js/save_data_success.js') }}"></script>
</head>
<body>
<h1>Excel Data</h1>
<h2>File Information:</h2>
<ul>
<li>Subcontractor: {{ file_info['Subcontractor'] }}</li>
<li>State: {{ file_info['State'] }}</li>
<li>District: {{ file_info['District'] }}</li>
<li>Block: {{ file_info['Block'] }}</li>
</ul>
{% if errors %}
<div class="errors">
<h2>Validation Errors:</h2>
<ul>
{% for error in errors %}
<li class="error">{{ error }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<h2>Data Table:</h2>
<form id="saveForm">
<div class="table-container">
<table>
<thead>
<tr>
<th>Row No</th>
{% for var in variables %}
<th>{{ var }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in data %}
<tr>
<td>{{ row['Row Number'] }}</td>
{% for var in variables %}
<td><input type="text" value="{{ row[var] }}"/></td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- Hidden fields for other necessary information -->
<input type="text" name="subcontractor_data" value="{{ subcontractor_data['Contractor_Id'] }}">
<input type="text" name="state_data" value="{{ state_data['State_ID'] }}">
<input type="text" name="district_data" value="{{ district_data['District_ID'] }}">
<input type="text" name="block_data" value="{{ block_data['Block_Id'] }}">
<input type="text" name="file_info" value="{{ file_info }}">
<input type="text" name="hold_columns" value="{{ hold_columns }}">
<input type="text" name="hold_counter" value="{{ hold_counter }}">
<input type="text" name="variables[]" value="{{ variables }}">
<input type="text" name="data[]" value="{{ data }}">
<!-- {% for row in data %}-->
<!-- <input type="text" name="data[]" value="{{ row | join(',') }}">-->
<!-- {% endfor %}-->
<button type="submit" class="save-button">Save Data</button>
</form>
<a href="/" class="back-button">Back to Dashboard</a>
</body>
</html>

View File

@@ -0,0 +1,372 @@
{% extends 'base.html' %}
{% block content %}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Contractor Report</title>
<!-- <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">-->
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/subcontractor_report.css') }}">
</head>
<body>
<div class="container">
<h2>Contractor Report</h2>
<div class="info">
<h2>Contractor Details</h2>
<div class="row2">
<div>
<label for="subcontractor">Subcontractor Name:</label>
<input type="text" id="subcontractor" name="subcontractor" value="{{ contInfo.Contractor_Name }}"
readonly/>
</div>
<div>
<label for="Address">Address :</label>
<textarea id="Address" name="Address" readonly>{{ contInfo.Address }}</textarea>
</div>
</div>
<div class="row3">
<div>
<label for="PAN_No">PAN No :</label>
<input type="text" id="PAN_No" name="PAN_No" value="{{ contInfo.PAN_No }}" readonly/>
</div>
<div>
<label for="Mobile_No">Mobile Number :</label>
<input type="text" id="Mobile_No" name="Mobile_No" value="{{ contInfo.Mobile_No }}" readonly/>
</div>
<div>
<label for="Email">Email :</label>
<input type="text" id="Email" name="Email" value="{{ contInfo.Email }}" readonly/>
</div>
</div>
<div class="row2">
<div>
<label for="GST_Registration_Type">GST Registration Type :</label>
<input type="text" id="GST_Registration_Type" name="GST_Registration_Type"
value="{{ contInfo.GST_Registration_Type }}" readonly/>
</div>
<div>
<label for="GST_No">GST No:</label>
<input type="text" id="GST_No" name="GST_No" value="{{ contInfo.GST_No }}" readonly/>
</div>
</div>
<div class="row3">
<div>
<label for="State">State :</label>
<input type="text" id="State" name="State" value="{{ contInfo.State_Name }}" readonly/>
</div>
<div>
<label for="District">District :</label>
<input type="text" id="District" name="District" value="{{ contInfo.District_Name }}" readonly/>
</div>
<div>
<label for="Block">Block :</label>
<input type="text" id="Block" name="Block" value="{{ contInfo.Block_Name }}" readonly/>
</div>
</div>
</div>
<h3>Total</h3>
<table class="total-table">
<tr>
<th colspan="2">{{current_date}}</th>
</tr>
<!-- <tr>-->
<!-- <th>Total Hold Amounnt</th>-->
<!-- <td>0</td>-->
<!-- </tr>-->
<tr>
<th>Advance / Suplus</th>
<td>{{total["sum_invo_final_amt"]+total["sum_gst_final_amt"]-total["sum_pay_total_amt"]}}</td>
</tr>
{% if hold_types %}
<tr>
{% for hold in hold_types %}
<th>{{ hold.hold_type }}</th>
<td>{{total["sum_invo_hold_amt"]}}</td>
{% endfor %}
</tr>
{% endif %}
<tr>
<th>Amount With TDS</th>
<td>{{total["sum_invo_tds_amt"]}}</td>
</tr>
</table>
<!-- {% if hold_types %}-->
<!-- <h3>Hold Types</h3>-->
<!-- <ul>-->
<!-- {% for hold in hold_types %}-->
<!-- <li>{{ hold.hold_type }}</li>-->
<!-- {% endfor %}-->
<!-- </ul>-->
<!-- {% endif %}-->
<h3>Invoice Details</h3>
<table>
<thead>
<tr>
<th>PMC No</th>
<th>Village Name</th>
<th>Work Type</th>
<th>Invoice Details</th>
<th>Invoice Date</th>
<th>Invoice No</th>
<th>Basic Amount</th>
<th>Debit</th>
<th>After Debit Amt</th>
<th>GST (18%)</th>
<th>Amount</th>
<th>TDS (1%)</th>
<th>SD (5%)</th>
<th>On Commission</th>
<th>Hydro Testing</th>
<!-- Dynamic Hold Types -->
{% set hold_types = invoices | map(attribute='hold_type') | unique | list %}
{% for hold in hold_types %}
<th>{{ hold }}</th>
{% endfor %}
<th>GST SD (18%)</th>
<th>Final Amount</th>
</tr>
</thead>
<tbody>
{% if invoices %}
{% for invoice in invoices %}
<tr>
<td>{{ invoice.PMC_No }}</td>
<td>{{ invoice.Village_Name.capitalize() }}</td>
<td>{{ invoice.Work_Type }}</td>
<td>{{ invoice.Invoice_Details }}</td>
<td>{{ invoice.Invoice_Date }}</td>
<td>{{ invoice.Invoice_No }}</td>
<td>{{ invoice.Basic_Amount }}</td>
<td>{{ invoice.Debit_Amount }}</td>
<td>{{ invoice.After_Debit_Amount }}</td>
<td>{{ invoice.GST_Amount }}</td>
<td>{{ invoice.Amount }}</td>
<td>{{ invoice.TDS_Amount }}</td>
<td>{{ invoice.SD_Amount }}</td>
<td>{{ invoice.On_Commission }}</td>
<td>{{ invoice.Hydro_Testing }}</td>
<!-- Dynamic Hold Amounts -->
{% set hold_types = invoices | map(attribute='hold_type') | unique | list %}
{% for hold in hold_types %}
<td>
{% if invoice.hold_type == hold %}
{{ invoice.hold_amount }}
{% else %}
0.00
{% endif %}
</td>
{% endfor %}
<td>{{ invoice.GST_SD_Amount }}</td>
<td>{{ invoice.Final_Amount }}</td>
</tr>
{% endfor %}
<tr>
<th colspan="6">Total</th>
<th>{{total["sum_invo_basic_amt"]}}</th>
<th>{{total["sum_invo_debit_amt"]}}</th>
<th>{{total["sum_invo_after_debit_amt"]}}</th>
<th>{{total["sum_invo_gst_amt"]}}</th>
<th>{{total["sum_invo_amt"]}}</th>
<th>{{total["sum_invo_tds_amt"]}}</th>
<th>{{total["sum_invo_ds_amt"]}}</th>
<th>{{total["sum_invo_on_commission"]}}</th>
<th>{{total["sum_invo_hydro_test"]}}</th>
{% set hold_types = invoices | map(attribute='hold_type') | unique | list %}
{% for hold in hold_types %}
<th>{{total["sum_invo_hold_amt"]}}</th>
{% endfor %}
<th>{{total["sum_invo_gst_sd_amt"]}}</th>
<th>{{total["sum_invo_final_amt"]}}</th>
</tr>
{% else %}
<tr>
<td colspan="{{ 17 + hold_types|length }}">No invoices found.</td>
</tr>
{% endif %}
</tbody>
</table>
<h3>Hold Release</h3>
<table>
<thead>
<tr>
<th>PMC No</th>
<th>Invoice No</th>
<th>Invoice Details</th>
<th>Basic Amount</th>
<th>Total Amount</th>
<th>UTR</th>
</tr>
</thead>
<tbody>
{% if hold_release %}
{% for hold in hold_release %}
<tr>
<td>{{ hold['PMC_No'] }}</td>
<td>{{ hold['Invoice_No'] }}</td>
<td>{{ hold['Invoice_Details'] }}</td>
<td>{{ hold['Basic_Amount'] }}</td>
<td>{{ hold['Total_Amount'] }}</td>
<td>{{ hold['UTR'] }}</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="6" style="text-align:center;">No data present</td>
</tr>
{% endif %}
</tbody>
</table>
<br>
<tr>
<h3>Credit Details</h3>
</tr>
<table>
<thead>
<tr>
<th>PMC No</th>
<th>Invoice Details</th>
<th>Basic Amount</th>
<th>Debit</th>
<th>After Debit Amt</th>
<th>GST Amount</th>
<th>Amount</th>
<th>Final Amount</th>
<th>Payment Amount</th>
<th>Total Amount</th>
<th>UTR</th>
</tr>
{% if credit_note %}
{% for credit in credit_note %}
<tr>
<td>{{ credit["PMC_No"] }}</td>
<td>{{ credit["Invoice_Details"] }}</td>
<td>{{ credit["Basic_Amount"] }}</td>
<td>{{ credit["Debit_Amount"] }}</td>
<td>{{ credit["After_Debit_Amount"] }}</td>
<td>{{ credit["GST_Amount"] }}</td>
<td>{{ credit["Amount"] }}</td>
<td>{{ credit["Final_Amount"] }}</td>
<td>{{ credit["Payment_Amount"] }}</td>
<td>{{ credit["Total_Amount"] }}</td>
<td>{{ credit["UTR"] }}</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="11">No Credit note found.</td>
</tr>
{% endif %}
</thead>
</table>
<h3>GST Release Note Details</h3>
<table>
<thead>
<tr>
<th>PMC No</th>
<th>Invoice No</th>
<th>Basic Amount</th>
<th>Final Amount</th>
</tr>
</thead>
<tbody>
{% if gst_rel %}
{% for gst in gst_rel %}
<tr>
<td>{{ gst.pmc_no }}</td>
<td>{{ gst.invoice_no }}</td>
<td>{{ gst.basic_amount }}</td>
<td>{{ gst.final_amount }}</td>
</tr>
{% endfor %}
<tr>
<th colspan="2">Total</th>
<th>{{total["sum_gst_basic_amt"]}}</th>
<th>{{total["sum_gst_final_amt"]}}</th>
</tr>
{% else %}
<tr>
<td colspan="4">No GST release found.</td>
</tr>
{% endif %}
</tbody>
</table>
<br>
<h3>Payment Details</h3>
<table>
<thead>
<tr>
<th>PMC No</th>
<th>Invoice No</th>
<th>Amount</th>
<th>TDS Amount @ 1% on BASIC AMOUNT</th>
<th>Total Amount Paid</th>
<th>UTR</th>
</tr>
</thead>
<tbody>
{% if payments %}
{% for pay in payments %}
<tr>
<td>{{ pay.pmc_no }}</td>
<td>{{ pay.invoice_no }}</td>
<td>{{ pay.Payment_Amount }}</td>
<td>{{ pay.TDS_Payment_Amount }}</td>
<td>{{ pay.Total_amount }}</td>
<td>{{ pay.utr}}</td>
</tr>
{% endfor %}
<tr>
<th colspan="2">Total</th>
<th>{{total["sum_pay_payment_amt"]}}</th>
<th>{{total["sum_pay_tds_payment_amt"]}}</th>
<th>{{total["sum_pay_total_amt"]}}</th>
<th></th>
</tr>
{% else %}
<tr>
<td colspan="6">No payment found.</td>
</tr>
{% endif %}
</tbody>
</table>
<a href="{{ url_for('download_report', contractor_id=contractor_id) }}" class="download-btn">Download Report</a>
</div>
</body>
{% endblock %}

View File

@@ -0,0 +1,24 @@
{% extends 'base.html' %}
{% block content %}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Upload Excel File</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/validateFileInput.js') }}"></script>
</head>
<body>
<h2>Upload Excel File</h2>
<div class="container">
<form action="/upload_excel_file" method="post" enctype="multipart/form-data"
onsubmit="return validateFileInput()">
<input type="file" name="file" accept=".xlsx,.xls">
<br><br>
<button type="submit">Upload</button>
</form>
</div>
</body>
{% endblock %}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
uploads/(DONE) Akram.xlsx Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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