diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..fb7cc38 --- /dev/null +++ b/app/__init__.py @@ -0,0 +1,47 @@ +from flask import Flask +from flask_sqlalchemy import SQLAlchemy +from app.config import Config + +db = SQLAlchemy() + +def create_app(): + app = Flask(__name__) + app.config.from_object(Config) + + db.init_app(app) + + # Register Blueprints + from app.routes.dashboard import dashboard_bp + from app.routes.file_import import file_import_bp + # from app.routes.user import user_bp + + app.register_blueprint(dashboard_bp) + app.register_blueprint(file_import_bp) + # app.register_blueprint(user_bp) + + from app.routes.subcontractor_routes import subcontractor_bp + app.register_blueprint(subcontractor_bp) + + return app + + + + + +# from flask import Flask +# from app.config import Config + +# def create_app(): +# app = Flask(__name__) +# app.config.from_object(Config) + +# # Register Blueprints +# from app.routes.dashboard import dashboard_bp +# from app.routes.file_import import file_import_bp +# from app.routes.user import user_bp + +# app.register_blueprint(dashboard_bp) +# app.register_blueprint(file_import_bp) +# app.register_blueprint(user_bp) + +# return app diff --git a/app/__pycache__/__init__.cpython-313.pyc b/app/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..ff00ddd Binary files /dev/null and b/app/__pycache__/__init__.cpython-313.pyc differ diff --git a/app/__pycache__/app.cpython-313.pyc b/app/__pycache__/app.cpython-313.pyc new file mode 100644 index 0000000..c1da547 Binary files /dev/null and b/app/__pycache__/app.cpython-313.pyc differ diff --git a/app/__pycache__/config.cpython-313.pyc b/app/__pycache__/config.cpython-313.pyc new file mode 100644 index 0000000..1e41384 Binary files /dev/null and b/app/__pycache__/config.cpython-313.pyc differ diff --git a/app/config.py b/app/config.py new file mode 100644 index 0000000..302f703 --- /dev/null +++ b/app/config.py @@ -0,0 +1,24 @@ +import os + +class Config: + + SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:root@localhost/comparisondb" + + SQLALCHEMY_TRACK_MODIFICATIONS = False + SECRET_KEY = "secret123" + + UPLOAD_FOLDER = "app/static/uploads/" + ALLOWED_EXTENSIONS = {"xlsx", "xls", "csv"} + + + +# class Config: +# SECRET_KEY = os.getenv("SECRET_KEY", "dev_key_12345") + +# UPLOAD_FOLDER = "app/static/uploads/" +# ALLOWED_EXTENSIONS = {"xlsx", "xls", "csv"} + +# DB_HOST = "localhost" +# DB_USER = "root" +# DB_PASSWORD = "root" +# DB_NAME = "comparisondb" diff --git a/app/logs/app.log b/app/logs/app.log new file mode 100644 index 0000000..e69de29 diff --git a/app/models/__init__.py b/app/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/models/__pycache__/__init__.cpython-313.pyc b/app/models/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..6f4a5dd Binary files /dev/null and b/app/models/__pycache__/__init__.cpython-313.pyc differ diff --git a/app/models/__pycache__/subcontractor_model.cpython-313.pyc b/app/models/__pycache__/subcontractor_model.cpython-313.pyc new file mode 100644 index 0000000..e8dc042 Binary files /dev/null and b/app/models/__pycache__/subcontractor_model.cpython-313.pyc differ diff --git a/app/models/__pycache__/trench_excavation_model.cpython-313.pyc b/app/models/__pycache__/trench_excavation_model.cpython-313.pyc new file mode 100644 index 0000000..a0bd829 Binary files /dev/null and b/app/models/__pycache__/trench_excavation_model.cpython-313.pyc differ diff --git a/app/models/__pycache__/user_model.cpython-313.pyc b/app/models/__pycache__/user_model.cpython-313.pyc new file mode 100644 index 0000000..db855aa Binary files /dev/null and b/app/models/__pycache__/user_model.cpython-313.pyc differ diff --git a/app/models/manhole_excavation_model.py b/app/models/manhole_excavation_model.py new file mode 100644 index 0000000..e69de29 diff --git a/app/models/subcontractor_model.py b/app/models/subcontractor_model.py new file mode 100644 index 0000000..598e274 --- /dev/null +++ b/app/models/subcontractor_model.py @@ -0,0 +1,21 @@ +from app import db +# from app.services.db_service import db +from datetime import datetime + +class Subcontractor(db.Model): + __tablename__ = "subcontractors" + + id = db.Column(db.Integer, primary_key=True) + subcontractor_name = db.Column(db.String(255), nullable=False) + address = db.Column(db.String(500)) + gst_no = db.Column(db.String(50)) + pan_no = db.Column(db.String(50)) + mobile_no = db.Column(db.String(20)) + email_id = db.Column(db.String(150)) + contact_person = db.Column(db.String(150)) + status = db.Column(db.String(20), default="Active") + created_at = db.Column(db.DateTime, default=datetime.utcnow) + + def __repr__(self): + return f"" + diff --git a/app/models/trench_excavation_model.py b/app/models/trench_excavation_model.py new file mode 100644 index 0000000..6df15ff --- /dev/null +++ b/app/models/trench_excavation_model.py @@ -0,0 +1,73 @@ +from app import db +from datetime import datetime + +class TrenchExcavation(db.Model): + __tablename__ = "trench_excavation" + + id = db.Column(db.Integer, primary_key=True) + # Foreign Key to Subcontractor table + subcontractor_id = db.Column(db.Integer, db.ForeignKey("subcontractors.id"), nullable=False) + # Relationship for easy access (subcontractor.subcontractor_name) + subcontractor = db.relationship("Subcontractor", backref="trench_records") + + # Basic Fields + Location = db.Column(db.String(255)) + MH_NO = db.Column(db.String(100)) + CC_length = db.Column(db.Float) + Invert_Level = db.Column(db.Float) + MH_Top_Level = db.Column(db.Float) + Ground_Level = db.Column(db.Float) + ID_of_MH_m = db.Column(db.Float) + Actual_Trench_Length = db.Column(db.Float) + Pipe_Dia_mm = db.Column(db.Float) + + Width_0_to_2_5 = db.Column(db.Float) + Width_2_5_to_3_0 = db.Column(db.Float) + Width_3_0_to_4_5 = db.Column(db.Float) + Width_4_5_to_6_0 = db.Column(db.Float) + + Upto_IL_Depth = db.Column(db.Float) + Cutting_Depth = db.Column(db.Float) + Avg_Depth = db.Column(db.Float) + + # Excavation categories + Soft_Murum_0_to_1_5 = db.Column(db.Float) + Soft_Murum_1_5_to_3_0 = db.Column(db.Float) + Soft_Murum_3_0_to_4_5 = db.Column(db.Float) + + Hard_Murum_0_to_1_5 = db.Column(db.Float) + Hard_Murum_1_5_to_3_0 = db.Column(db.Float) + + Soft_Rock_0_to_1_5 = db.Column(db.Float) + Soft_Rock_1_5_to_3_0 = db.Column(db.Float) + + Hard_Rock_0_to_1_5 = db.Column(db.Float) + Hard_Rock_1_5_to_3_0 = db.Column(db.Float) + Hard_Rock_3_0_to_4_5 = db.Column(db.Float) + Hard_Rock_4_5_to_6_0 = db.Column(db.Float) + Hard_Rock_6_0_to_7_5 = db.Column(db.Float) + + # Totals + Soft_Murum_0_to_1_5_total = db.Column(db.Float) + Soft_Murum_1_5_to_3_0_total = db.Column(db.Float) + Soft_Murum_3_0_to_4_5_total = db.Column(db.Float) + + Hard_Murum_0_to_1_5_total = db.Column(db.Float) + Hard_Murum_1_5_and_above_total = db.Column(db.Float) + + Soft_Rock_0_to_1_5_total = db.Column(db.Float) + Soft_Rock_1_5_and_above_total = db.Column(db.Float) + + Hard_Rock_0_to_1_5_total = db.Column(db.Float) + Hard_Rock_1_5_and_above_total = db.Column(db.Float) + Hard_Rock_3_0_to_4_5_total = db.Column(db.Float) + Hard_Rock_4_5_to_6_0_total = db.Column(db.Float) + Hard_Rock_6_0_to_7_5_total = db.Column(db.Float) + + Remarks = db.Column(db.String(500)) + Total = db.Column(db.Float) + + created_at = db.Column(db.DateTime, default=datetime.utcnow) + + def __repr__(self): + return f"" diff --git a/app/models/user_model.py b/app/models/user_model.py new file mode 100644 index 0000000..63be6c1 --- /dev/null +++ b/app/models/user_model.py @@ -0,0 +1,21 @@ +# from app.services.db_service import db +# from werkzeug.security import generate_password_hash, check_password_hash + +# class User(db.Model): +# id = db.Column(db.Integer, primary_key=True) +# name = db.Column(db.String(120)) +# email = db.Column(db.String(120), unique=True) +# password_hash = db.Column(db.String(255)) + +# def set_password(self, password): +# self.password_hash = generate_password_hash(password) + +# def check_password(self, password): +# return check_password_hash(self.password_hash, password) + + +class User: + def __init__(self, id, name, email): + self.id = id + self.name = name + self.email = email diff --git a/app/routes/__init__.py b/app/routes/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/routes/__pycache__/__init__.cpython-313.pyc b/app/routes/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..772ec62 Binary files /dev/null and b/app/routes/__pycache__/__init__.cpython-313.pyc differ diff --git a/app/routes/__pycache__/auth.cpython-313.pyc b/app/routes/__pycache__/auth.cpython-313.pyc new file mode 100644 index 0000000..08144c0 Binary files /dev/null and b/app/routes/__pycache__/auth.cpython-313.pyc differ diff --git a/app/routes/__pycache__/dashboard.cpython-313.pyc b/app/routes/__pycache__/dashboard.cpython-313.pyc new file mode 100644 index 0000000..162cc5d Binary files /dev/null and b/app/routes/__pycache__/dashboard.cpython-313.pyc differ diff --git a/app/routes/__pycache__/file_import.cpython-313.pyc b/app/routes/__pycache__/file_import.cpython-313.pyc new file mode 100644 index 0000000..8370c01 Binary files /dev/null and b/app/routes/__pycache__/file_import.cpython-313.pyc differ diff --git a/app/routes/__pycache__/subcontractor_routes.cpython-313.pyc b/app/routes/__pycache__/subcontractor_routes.cpython-313.pyc new file mode 100644 index 0000000..55b182e Binary files /dev/null and b/app/routes/__pycache__/subcontractor_routes.cpython-313.pyc differ diff --git a/app/routes/__pycache__/user.cpython-313.pyc b/app/routes/__pycache__/user.cpython-313.pyc new file mode 100644 index 0000000..c935191 Binary files /dev/null and b/app/routes/__pycache__/user.cpython-313.pyc differ diff --git a/app/routes/auth.py b/app/routes/auth.py new file mode 100644 index 0000000..cd0cb10 --- /dev/null +++ b/app/routes/auth.py @@ -0,0 +1,31 @@ +from flask import Blueprint, request, render_template, redirect, flash, session +from app.services.user_service import UserService + +auth_bp = Blueprint("auth", __name__, url_prefix="/auth") + +# LOGIN PAGE +@auth_bp.route("/login", methods=["GET", "POST"]) +def login(): + if request.method == "POST": + user = UserService.validate_login( + request.form["email"], + request.form["password"] + ) + if user: + session["user_id"] = user.id + return redirect("/dashboard") + flash("Invalid credentials", "danger") + return render_template("login.html") + +# REGISTER API ONLY +@auth_bp.route("/register", methods=["POST"]) +def register(): + data = request.json + UserService.register_user(data["name"], data["email"], data["password"]) + return {"message": "User registered successfully"}, 201 + +# LOGOUT +@auth_bp.route("/logout") +def logout(): + session.clear() + return redirect("/auth/login") diff --git a/app/routes/dashboard.py b/app/routes/dashboard.py new file mode 100644 index 0000000..fa4b6e9 --- /dev/null +++ b/app/routes/dashboard.py @@ -0,0 +1,8 @@ +from flask import Blueprint, render_template + +dashboard_bp = Blueprint("dashboard", __name__) + +@dashboard_bp.route("/") +@dashboard_bp.route("/dashboard") +def dashboard(): + return render_template("dashboard.html", title="Dashboard") diff --git a/app/routes/file_import.py b/app/routes/file_import.py new file mode 100644 index 0000000..88aae68 --- /dev/null +++ b/app/routes/file_import.py @@ -0,0 +1,21 @@ +from flask import Blueprint, render_template, request, flash +from app.services.file_service import FileService +from app.models.subcontractor_model import Subcontractor + +file_import_bp = Blueprint("file_import", __name__, url_prefix="/file") + +@file_import_bp.route("/import", methods=["GET", "POST"]) +def import_file(): + subcontractors = Subcontractor.query.all() + + if request.method == "POST": + file = request.files.get("file") + subcontractor_id = request.form.get("subcontractor_id") + file_type = request.form.get("file_type") + + service = FileService() + success, msg = service.handle_file_upload(file, subcontractor_id, file_type) + + flash(msg, "success" if success else "danger") + + return render_template("file_import.html", title="File Import", subcontractors=subcontractors) diff --git a/app/routes/subcontractor_routes.py b/app/routes/subcontractor_routes.py new file mode 100644 index 0000000..5fd3b71 --- /dev/null +++ b/app/routes/subcontractor_routes.py @@ -0,0 +1,64 @@ +from flask import Blueprint, render_template, request, redirect, flash +from app import db +from app.models.subcontractor_model import Subcontractor + +subcontractor_bp = Blueprint("subcontractor", __name__, url_prefix="/subcontractor") + +# ---------------- ADD ----------------- +@subcontractor_bp.route("/add") +def add_subcontractor(): + return render_template("subcontractor/add.html") + +@subcontractor_bp.route("/save", methods=["POST"]) +def save_subcontractor(): + subcontractor = Subcontractor( + subcontractor_name=request.form.get("subcontractor_name"), + contact_person=request.form.get("contact_person"), + mobile_no=request.form.get("mobile_no"), + email_id=request.form.get("email_id"), + gst_no=request.form.get("gst_no") + ) + db.session.add(subcontractor) + db.session.commit() + + flash("Subcontractor added successfully!", "success") + return redirect("/subcontractor/list") + +# ---------------- LIST ----------------- +@subcontractor_bp.route("/list") +def subcontractor_list(): + subcontractors = Subcontractor.query.all() + return render_template("subcontractor/list.html", subcontractors=subcontractors) + +# ---------------- EDIT ----------------- +@subcontractor_bp.route("/edit/") +def edit_subcontractor(id): + subcontractor = Subcontractor.query.get_or_404(id) + return render_template("subcontractor/edit.html", subcontractor=subcontractor) + +# ---------------- UPDATE ----------------- +@subcontractor_bp.route("/update/", methods=["POST"]) +def update_subcontractor(id): + subcontractor = Subcontractor.query.get_or_404(id) + + subcontractor.subcontractor_name = request.form.get("subcontractor_name") + subcontractor.contact_person = request.form.get("contact_person") + subcontractor.mobile_no = request.form.get("mobile_no") + subcontractor.email_id = request.form.get("email_id") + subcontractor.gst_no = request.form.get("gst_no") + + db.session.commit() + + flash("Subcontractor updated successfully!", "success") + return redirect("/subcontractor/list") + +# ---------------- DELETE ----------------- +@subcontractor_bp.route("/delete/") +def delete_subcontractor(id): + subcontractor = Subcontractor.query.get_or_404(id) + + db.session.delete(subcontractor) + db.session.commit() + + flash("Subcontractor deleted successfully!", "success") + return redirect("/subcontractor/list") diff --git a/app/routes/user.py b/app/routes/user.py new file mode 100644 index 0000000..12757bc --- /dev/null +++ b/app/routes/user.py @@ -0,0 +1,9 @@ +from flask import Blueprint, render_template +from app.services.user_service import UserService + +user_bp = Blueprint("user", __name__, url_prefix="/user") + +@user_bp.route("/list") +def list_users(): + users = UserService().get_all_users() + return render_template("users.html", users=users, title="Users") diff --git a/app/services/__init__.py b/app/services/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/services/__pycache__/__init__.cpython-313.pyc b/app/services/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..be71a81 Binary files /dev/null and b/app/services/__pycache__/__init__.cpython-313.pyc differ diff --git a/app/services/__pycache__/db_service.cpython-313.pyc b/app/services/__pycache__/db_service.cpython-313.pyc new file mode 100644 index 0000000..ea7c9aa Binary files /dev/null and b/app/services/__pycache__/db_service.cpython-313.pyc differ diff --git a/app/services/__pycache__/file_service.cpython-313.pyc b/app/services/__pycache__/file_service.cpython-313.pyc new file mode 100644 index 0000000..43b0dd9 Binary files /dev/null and b/app/services/__pycache__/file_service.cpython-313.pyc differ diff --git a/app/services/__pycache__/user_service.cpython-313.pyc b/app/services/__pycache__/user_service.cpython-313.pyc new file mode 100644 index 0000000..70398f4 Binary files /dev/null and b/app/services/__pycache__/user_service.cpython-313.pyc differ diff --git a/app/services/db_service.py b/app/services/db_service.py new file mode 100644 index 0000000..f8adddc --- /dev/null +++ b/app/services/db_service.py @@ -0,0 +1,19 @@ +from flask_sqlalchemy import SQLAlchemy +from flask_migrate import Migrate + +db = SQLAlchemy() +migrate = Migrate() + + +# import mysql.connector +# from app.config import Config + +# class DBService: + +# def connect(self): +# return mysql.connector.connect( +# host=Config.DB_HOST, +# user=Config.DB_USER, +# password=Config.DB_PASSWORD, +# database=Config.DB_NAME +# ) diff --git a/app/services/file_service.py b/app/services/file_service.py new file mode 100644 index 0000000..20d9929 --- /dev/null +++ b/app/services/file_service.py @@ -0,0 +1,103 @@ +# app/services/file_service.py + +import os +import pandas as pd +from werkzeug.utils import secure_filename +from app.config import Config +from app import db +from app.models.trench_excavation_model import TrenchExcavation +from app.utils.file_utils import ensure_upload_folder + + +class FileService: + + def allowed_file(self, filename): + return "." in filename and filename.rsplit(".", 1)[1].lower() in Config.ALLOWED_EXTENSIONS + + def handle_file_upload(self, file, subcontractor_id, file_type): + + if not subcontractor_id: + return False, "Please select subcontractor." + if not file_type: + return False, "Please select file type." + if not file or file.filename == "": + return False, "No file selected." + if not self.allowed_file(file.filename): + return False, "Invalid file type! Allowed: CSV, XLSX, XLS" + + ensure_upload_folder() + + folder = os.path.join(Config.UPLOAD_FOLDER, f"sub_{subcontractor_id}") + os.makedirs(folder, exist_ok=True) + + filename = secure_filename(file.filename) + filepath = os.path.join(folder, filename) + file.save(filepath) + + try: + df = pd.read_csv(filepath) if filename.endswith(".csv") else pd.read_excel(filepath) + + print("\n=== Uploaded File Preview ===") + print(df.head()) + print("=============================\n") + + if file_type == "trench_excavation": + return self.process_trench_excavation(df, subcontractor_id) + + return True, "File uploaded successfully." + + except Exception as e: + return False, f"Processing failed: {e}" + + + + # CLEAN & SAVE TRENCH EXCAVATION DATA + def process_trench_excavation(self, df, subcontractor_id): + + # Clean column names (strip whitespace) + df.columns = [str(c).strip() for c in df.columns] + + # If the sheet has merged cells -> forward fill Location + if "Location" in df.columns: + df["Location"] = df["Location"].ffill() + + # REMOVE empty rows + df = df.dropna(how="all") + + # Identify missing location rows before insert + missing_loc = df[df["Location"].isna() | (df["Location"].astype(str).str.strip() == "")] + if not missing_loc.empty: + return False, f"Error: Some rows have empty Location. Rows: {missing_loc.index.tolist()}" + + saved_count = 0 + + try: + for index, row in df.iterrows(): + + record_data = {} + + # Insert only fields that exist in model + for col in df.columns: + if hasattr(TrenchExcavation, col): + value = row[col] + + # Normalize empty values + if pd.isna(value) or str(value).strip() in ["", "-", "—", "nan", "NaN"]: + value = None + + record_data[col] = value + + record = TrenchExcavation( + subcontractor_id=subcontractor_id, + **record_data + ) + + db.session.add(record) + saved_count += 1 + + db.session.commit() + return True, f"Trench Excavation data saved successfully. Total rows: {saved_count}" + + except Exception as e: + db.session.rollback() + return False, f"Trench Excavation Save Failed: {e}" diff --git a/app/services/user_service.py b/app/services/user_service.py new file mode 100644 index 0000000..88da95a --- /dev/null +++ b/app/services/user_service.py @@ -0,0 +1,47 @@ +# from app.models.user_model import User +# from app.services.db_service import db +# import logging + +# class UserService: + +# @staticmethod +# def register_user(name, email, password): +# user = User(name=name, email=email) +# user.set_password(password) +# db.session.add(user) +# db.session.commit() +# logging.info(f"New user registered: {email}") +# return user + +# @staticmethod +# def validate_login(email, password): +# user = User.query.filter_by(email=email).first() +# if user and user.check_password(password): +# logging.info(f"Login success: {email}") +# return user +# logging.warning(f"Login failed for: {email}") +# return None + +# @staticmethod +# def get_all_users(): +# return User.query.all() + + +from app.services.db_service import DBService +from app.models.user_model import User + +class UserService: + + def get_all_users(self): + db = DBService().connect() + cursor = db.cursor(dictionary=True) + + cursor.execute("SELECT id, name, email FROM users") + rows = cursor.fetchall() + + users = [User(**row) for row in rows] + + cursor.close() + db.close() + + return users diff --git a/app/static/css/subcontractor.css b/app/static/css/subcontractor.css new file mode 100644 index 0000000..26f4913 --- /dev/null +++ b/app/static/css/subcontractor.css @@ -0,0 +1,35 @@ +body { + background: #f5f7fa; + font-family: Arial; + padding: 40px; +} + +form { + width: 420px; + padding: 20px; + background: #fff; + border-radius: 8px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); +} + +label { + margin-top: 10px; + display: block; + font-weight: bold; +} + +input, +textarea { + width: 100%; + padding: 8px; + margin-top: 4px; +} + +button { + margin-top: 20px; + padding: 10px 20px; + background: #0055ff; + color: #fff; + border: 0; + cursor: pointer; +} \ No newline at end of file diff --git a/app/static/uploads/sub_3/test_comparison.xlsx b/app/static/uploads/sub_3/test_comparison.xlsx new file mode 100644 index 0000000..61dde37 Binary files /dev/null and b/app/static/uploads/sub_3/test_comparison.xlsx differ diff --git a/app/static/uploads/sub_4/testing11.xlsx b/app/static/uploads/sub_4/testing11.xlsx new file mode 100644 index 0000000..dc3cba9 Binary files /dev/null and b/app/static/uploads/sub_4/testing11.xlsx differ diff --git a/app/templates/base.html b/app/templates/base.html new file mode 100644 index 0000000..2169bd2 --- /dev/null +++ b/app/templates/base.html @@ -0,0 +1,64 @@ + + + + + + + {{ title if title else "IndustryBase" }} + + + + + + + + + +
+ {% with messages = get_flashed_messages(with_categories=true) %} + {% for category, message in messages %} +
+ {{ message }} + +
+ {% endfor %} + {% endwith %} +
+ +
+ {% block content %}{% endblock %} +
+ + + + + + \ No newline at end of file diff --git a/app/templates/dashboard.html b/app/templates/dashboard.html new file mode 100644 index 0000000..a14ea00 --- /dev/null +++ b/app/templates/dashboard.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} + +{% block content %} +

Dashboard

+ +
+
Welcome to Comparison Project
+

This is dashboard panel.

+
+{% endblock %} \ No newline at end of file diff --git a/app/templates/file_import.html b/app/templates/file_import.html new file mode 100644 index 0000000..211d753 --- /dev/null +++ b/app/templates/file_import.html @@ -0,0 +1,39 @@ +{% extends "base.html" %} + +{% block content %} +

File Import

+ +
+ +
+ + + + + + + + + + + + + + +
+ +
+{% endblock %} \ No newline at end of file diff --git a/app/templates/list_user.html b/app/templates/list_user.html new file mode 100644 index 0000000..ae534d6 --- /dev/null +++ b/app/templates/list_user.html @@ -0,0 +1,28 @@ +{% extends "base.html" %} + +{% block content %} +

Users List

+ +
+ + + + + + + + + + + {% for user in users %} + + + + + + {% endfor %} + +
IDNameEmail
{{ user.id }}{{ user.name }}{{ user.email }}
+
+ +{% endblock %} \ No newline at end of file diff --git a/app/templates/login.html b/app/templates/login.html new file mode 100644 index 0000000..988bd47 --- /dev/null +++ b/app/templates/login.html @@ -0,0 +1,17 @@ +{% extends "base.html" %} +{% block content %} +

Login

+ +
+
+ + + + + + + + +
+
+{% endblock %} \ No newline at end of file diff --git a/app/templates/register.html b/app/templates/register.html new file mode 100644 index 0000000..d09a31b --- /dev/null +++ b/app/templates/register.html @@ -0,0 +1,20 @@ +{% extends "base.html" %} +{% block content %} +

User Registration

+ +
+
+ + + + + + + + + + + +
+
+{% endblock %} \ No newline at end of file diff --git a/app/templates/subcontractor/add.html b/app/templates/subcontractor/add.html new file mode 100644 index 0000000..61d15fa --- /dev/null +++ b/app/templates/subcontractor/add.html @@ -0,0 +1,40 @@ +{% extends "base.html" %} +{% block content %} + +
+ +

Add New Subcontractor

+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+ +
+ +{% endblock %} \ No newline at end of file diff --git a/app/templates/subcontractor/edit.html b/app/templates/subcontractor/edit.html new file mode 100644 index 0000000..4c4c037 --- /dev/null +++ b/app/templates/subcontractor/edit.html @@ -0,0 +1,41 @@ +{% extends "base.html" %} +{% block content %} + +
+

Edit Subcontractor

+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + + Back + +
+
+ +{% endblock %} \ No newline at end of file diff --git a/app/templates/subcontractor/list.html b/app/templates/subcontractor/list.html new file mode 100644 index 0000000..2ad86f0 --- /dev/null +++ b/app/templates/subcontractor/list.html @@ -0,0 +1,38 @@ +{% extends "base.html" %} +{% block content %} + +
+

Subcontractor List

+ + + + + + + + + + + + + + + {% for s in subcontractors %} + + + + + + + + + {% endfor %} + +
IDNameMobileEmailGST NoAction
{{ s.id }}{{ s.subcontractor_name }}{{ s.mobile_no }}{{ s.email_id }}{{ s.gst_no }} + Edit + Delete +
+
+ +{% endblock %} \ No newline at end of file diff --git a/app/templates/users.htm b/app/templates/users.htm new file mode 100644 index 0000000..ae534d6 --- /dev/null +++ b/app/templates/users.htm @@ -0,0 +1,28 @@ +{% extends "base.html" %} + +{% block content %} +

Users List

+ +
+ + + + + + + + + + + {% for user in users %} + + + + + + {% endfor %} + +
IDNameEmail
{{ user.id }}{{ user.name }}{{ user.email }}
+
+ +{% endblock %} \ No newline at end of file diff --git a/app/utils/__pycache__/file_utils.cpython-313.pyc b/app/utils/__pycache__/file_utils.cpython-313.pyc new file mode 100644 index 0000000..495d14e Binary files /dev/null and b/app/utils/__pycache__/file_utils.cpython-313.pyc differ diff --git a/app/utils/file_utils.py b/app/utils/file_utils.py new file mode 100644 index 0000000..8a79d69 --- /dev/null +++ b/app/utils/file_utils.py @@ -0,0 +1,6 @@ +import os +from app.config import Config + +def ensure_upload_folder(): + if not os.path.exists(Config.UPLOAD_FOLDER): + os.makedirs(Config.UPLOAD_FOLDER) diff --git a/app/utils/helpers.py b/app/utils/helpers.py new file mode 100644 index 0000000..2ab63b9 --- /dev/null +++ b/app/utils/helpers.py @@ -0,0 +1,2 @@ +def is_logged_in(session): + return session.get("user_id") is not None diff --git a/instance/comparisondb.db b/instance/comparisondb.db new file mode 100644 index 0000000..3f771ff Binary files /dev/null and b/instance/comparisondb.db differ diff --git a/logs/app.log b/logs/app.log new file mode 100644 index 0000000..3b781b9 --- /dev/null +++ b/logs/app.log @@ -0,0 +1,200 @@ +2025-12-09 13:11:05,606 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5000 +2025-12-09 13:11:05,607 | INFO | Press CTRL+C to quit +2025-12-09 13:11:05,608 | INFO | * Restarting with stat +2025-12-09 13:11:06,239 | WARNING | * Debugger is active! +2025-12-09 13:11:06,240 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:11:48,880 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5000 +2025-12-09 13:11:48,881 | INFO | Press CTRL+C to quit +2025-12-09 13:11:48,882 | INFO | * Restarting with stat +2025-12-09 13:11:49,519 | WARNING | * Debugger is active! +2025-12-09 13:11:49,521 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:12:05,727 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\services\\user_service.py', reloading +2025-12-09 13:12:05,826 | INFO | * Restarting with stat +2025-12-09 13:12:06,499 | WARNING | * Debugger is active! +2025-12-09 13:12:06,501 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:12:09,545 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\config.py', reloading +2025-12-09 13:12:09,654 | INFO | * Restarting with stat +2025-12-09 13:12:10,286 | WARNING | * Debugger is active! +2025-12-09 13:12:10,288 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:12:12,311 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\routes\\auth.py', reloading +2025-12-09 13:12:12,407 | INFO | * Restarting with stat +2025-12-09 13:12:13,071 | WARNING | * Debugger is active! +2025-12-09 13:12:13,072 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:12:16,128 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\config.py', reloading +2025-12-09 13:12:16,257 | INFO | * Restarting with stat +2025-12-09 13:12:16,898 | WARNING | * Debugger is active! +2025-12-09 13:12:16,900 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:12:20,944 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\routes\\user.py', reloading +2025-12-09 13:12:21,042 | INFO | * Restarting with stat +2025-12-09 13:12:21,719 | WARNING | * Debugger is active! +2025-12-09 13:12:21,721 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:12:23,762 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\routes\\file_import.py', reloading +2025-12-09 13:12:23,870 | INFO | * Restarting with stat +2025-12-09 13:12:24,505 | WARNING | * Debugger is active! +2025-12-09 13:12:24,507 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:12:27,561 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\services\\__init__.py', reloading +2025-12-09 13:12:27,670 | INFO | * Restarting with stat +2025-12-09 13:12:28,294 | WARNING | * Debugger is active! +2025-12-09 13:12:28,296 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:12:31,336 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\services\\db_service.py', reloading +2025-12-09 13:12:31,448 | INFO | * Restarting with stat +2025-12-09 13:12:32,097 | WARNING | * Debugger is active! +2025-12-09 13:12:32,099 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:13:05,662 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\config.py', reloading +2025-12-09 13:13:05,773 | INFO | * Restarting with stat +2025-12-09 13:13:06,466 | WARNING | * Debugger is active! +2025-12-09 13:13:06,469 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:13:10,944 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5000 +2025-12-09 13:13:10,944 | INFO | Press CTRL+C to quit +2025-12-09 13:13:10,945 | INFO | * Restarting with stat +2025-12-09 13:13:11,623 | WARNING | * Debugger is active! +2025-12-09 13:13:11,625 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:14:11,295 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\run.py', reloading +2025-12-09 13:14:11,393 | INFO | * Restarting with stat +2025-12-09 13:14:12,004 | WARNING | * Debugger is active! +2025-12-09 13:14:12,006 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:14:32,108 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:14:32,109 | INFO | Press CTRL+C to quit +2025-12-09 13:14:32,110 | INFO | * Restarting with stat +2025-12-09 13:14:32,699 | WARNING | * Debugger is active! +2025-12-09 13:14:32,701 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:15:58,632 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\run.py', reloading +2025-12-09 13:15:58,733 | INFO | * Restarting with stat +2025-12-09 13:15:59,415 | WARNING | * Debugger is active! +2025-12-09 13:15:59,416 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:16:03,475 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\run.py', reloading +2025-12-09 13:16:03,583 | INFO | * Restarting with stat +2025-12-09 13:16:04,204 | WARNING | * Debugger is active! +2025-12-09 13:16:04,206 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:16:33,504 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\run.py', reloading +2025-12-09 13:16:33,605 | INFO | * Restarting with stat +2025-12-09 13:16:34,213 | WARNING | * Debugger is active! +2025-12-09 13:16:34,215 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:16:41,815 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5000 +2025-12-09 13:16:41,816 | INFO | Press CTRL+C to quit +2025-12-09 13:18:12,302 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5000 +2025-12-09 13:18:12,302 | INFO | Press CTRL+C to quit +2025-12-09 13:22:07,114 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:22:07,114 | INFO | Press CTRL+C to quit +2025-12-09 13:22:07,116 | INFO | * Restarting with stat +2025-12-09 13:22:07,935 | WARNING | * Debugger is active! +2025-12-09 13:22:07,937 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:23:21,204 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\run.py', reloading +2025-12-09 13:23:21,305 | INFO | * Restarting with stat +2025-12-09 13:24:06,973 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:24:06,973 | INFO | Press CTRL+C to quit +2025-12-09 13:24:06,974 | INFO | * Restarting with stat +2025-12-09 13:24:07,689 | WARNING | * Debugger is active! +2025-12-09 13:24:07,691 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:24:36,315 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\app.py', reloading +2025-12-09 13:24:36,418 | INFO | * Restarting with stat +2025-12-09 13:24:37,074 | WARNING | * Debugger is active! +2025-12-09 13:24:37,076 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:26:54,442 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\__init__.py', reloading +2025-12-09 13:26:54,543 | INFO | * Restarting with stat +2025-12-09 13:26:59,170 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:26:59,170 | INFO | Press CTRL+C to quit +2025-12-09 13:26:59,171 | INFO | * Restarting with stat +2025-12-09 13:26:59,827 | WARNING | * Debugger is active! +2025-12-09 13:26:59,829 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:28:47,631 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\__init__.py', reloading +2025-12-09 13:28:47,747 | INFO | * Restarting with stat +2025-12-09 13:28:48,478 | WARNING | * Debugger is active! +2025-12-09 13:28:48,480 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:28:51,150 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:28:51,151 | INFO | Press CTRL+C to quit +2025-12-09 13:28:51,153 | INFO | * Restarting with stat +2025-12-09 13:28:51,788 | WARNING | * Debugger is active! +2025-12-09 13:28:51,790 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:28:54,904 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\__init__.py', reloading +2025-12-09 13:28:55,010 | INFO | * Restarting with stat +2025-12-09 13:28:55,608 | WARNING | * Debugger is active! +2025-12-09 13:28:55,610 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:28:56,644 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\__init__.py', reloading +2025-12-09 13:28:56,752 | INFO | * Restarting with stat +2025-12-09 13:29:04,454 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:29:04,454 | INFO | Press CTRL+C to quit +2025-12-09 13:29:04,455 | INFO | * Restarting with stat +2025-12-09 13:29:05,096 | WARNING | * Debugger is active! +2025-12-09 13:29:05,098 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:30:01,657 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:30:01,657 | INFO | Press CTRL+C to quit +2025-12-09 13:30:01,658 | INFO | * Restarting with stat +2025-12-09 13:30:02,278 | WARNING | * Debugger is active! +2025-12-09 13:30:02,280 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:30:27,872 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:30:27,872 | INFO | Press CTRL+C to quit +2025-12-09 13:30:27,873 | INFO | * Restarting with stat +2025-12-09 13:30:28,474 | WARNING | * Debugger is active! +2025-12-09 13:30:28,476 | INFO | * Debugger PIN: 105-645-384 +2025-12-09 13:33:22,709 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:33:22,709 | INFO | Press CTRL+C to quit +2025-12-09 13:33:22,710 | INFO | * Restarting with stat +2025-12-09 13:33:23,778 | WARNING | * Debugger is active! +2025-12-09 13:33:23,781 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:33:29,939 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\services\\db_service.py', reloading +2025-12-09 13:33:30,080 | INFO | * Restarting with stat +2025-12-09 13:33:44,462 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:33:44,462 | INFO | Press CTRL+C to quit +2025-12-09 13:33:44,464 | INFO | * Restarting with stat +2025-12-09 13:33:45,216 | WARNING | * Debugger is active! +2025-12-09 13:33:45,218 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:35:23,298 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:35:23,299 | INFO | Press CTRL+C to quit +2025-12-09 13:35:23,301 | INFO | * Restarting with stat +2025-12-09 13:35:24,098 | WARNING | * Debugger is active! +2025-12-09 13:35:24,100 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:38:25,991 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\__init__.py', reloading +2025-12-09 13:38:26,126 | INFO | * Restarting with stat +2025-12-09 13:38:27,120 | WARNING | * Debugger is active! +2025-12-09 13:38:27,122 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:38:37,386 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\config.py', reloading +2025-12-09 13:38:37,513 | INFO | * Restarting with stat +2025-12-09 13:38:38,297 | WARNING | * Debugger is active! +2025-12-09 13:38:38,300 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:38:45,485 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\run.py', reloading +2025-12-09 13:38:45,605 | INFO | * Restarting with stat +2025-12-09 13:38:46,348 | WARNING | * Debugger is active! +2025-12-09 13:38:46,350 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:38:55,109 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:38:55,109 | INFO | Press CTRL+C to quit +2025-12-09 13:38:55,110 | INFO | * Restarting with stat +2025-12-09 13:38:55,959 | WARNING | * Debugger is active! +2025-12-09 13:38:55,961 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:39:27,813 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\__init__.py', reloading +2025-12-09 13:39:27,937 | INFO | * Restarting with stat +2025-12-09 13:39:28,684 | WARNING | * Debugger is active! +2025-12-09 13:39:28,687 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:40:00,602 | INFO | * Detected change in 'C:\\Work\\lcepl_Projects\\Comparison Project\\app\\__init__.py', reloading +2025-12-09 13:40:00,728 | INFO | * Restarting with stat +2025-12-09 13:40:01,428 | WARNING | * Debugger is active! +2025-12-09 13:40:01,430 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 13:40:21,531 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 13:40:21,531 | INFO | Press CTRL+C to quit +2025-12-09 13:40:21,533 | INFO | * Restarting with stat +2025-12-09 13:40:22,307 | WARNING | * Debugger is active! +2025-12-09 13:40:22,309 | INFO | * Debugger PIN: 697-115-033 +2025-12-09 14:03:58,363 | INFO | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. + * Running on http://127.0.0.1:5001 +2025-12-09 14:03:58,363 | INFO | Press CTRL+C to quit +2025-12-09 14:03:58,364 | INFO | * Restarting with stat +2025-12-09 14:03:59,038 | WARNING | * Debugger is active! +2025-12-09 14:03:59,041 | INFO | * Debugger PIN: 697-115-033 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..50eb16d --- /dev/null +++ b/requirements.txt @@ -0,0 +1,7 @@ +Flask +pandas +openpyxl +xlrd +Werkzeug +python-dotenv +cryptography \ No newline at end of file diff --git a/run.py b/run.py new file mode 100644 index 0000000..ce951e0 --- /dev/null +++ b/run.py @@ -0,0 +1,9 @@ +from app import create_app, db + +app = create_app() + +with app.app_context(): + db.create_all() + +if __name__ == "__main__": + app.run(debug=True, port=5001)