From 06fe162198cada17f62bb10babd709b88e614509 Mon Sep 17 00:00:00 2001 From: pjpatil12 Date: Fri, 7 Aug 2026 13:51:58 +0530 Subject: [PATCH 1/2] edit .gitignore file --- .gitignore | 5 ++++- logs/app.log | 3 --- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 2eba46a..f5b87c4 100644 --- a/.gitignore +++ b/.gitignore @@ -11,8 +11,11 @@ app/static/uploads/ # Ignore env files venv -# Ignore Log files ss +# Ignore Log files logs/ +logs/app.log +logs/debug.log +logs/error.log *.log diff --git a/logs/app.log b/logs/app.log index 16c8000..e69de29 100644 --- a/logs/app.log +++ b/logs/app.log @@ -1,3 +0,0 @@ -2026-08-06 12:44:45 | INFO | User=System | IP=- | - | - | ====================================================================== -2026-08-06 12:44:45 | INFO | User=System | IP=- | - | - | Application Started Successfully -2026-08-06 12:44:45 | INFO | User=System | IP=- | - | - | ====================================================================== -- 2.49.1 From 4baf8378c7b03f4a5f604eee5f48ad1e89637535 Mon Sep 17 00:00:00 2001 From: pjpatil12 Date: Sat, 8 Aug 2026 10:34:07 +0530 Subject: [PATCH 2/2] Added on Client rate model --- app/models/client_rate_model.py | 20 + app/models/rate_model.py | 0 app/routes/engineering_master_routes.py | 66 +++- app/services/client_rate_service.py | 97 +++++ app/templates/engineering/client_rate.html | 346 ++++++++++++++++++ .../engineering/contractor_rate.html | 50 +-- app/templates/engineering/index.html | 4 +- 7 files changed, 545 insertions(+), 38 deletions(-) create mode 100644 app/models/client_rate_model.py delete mode 100644 app/models/rate_model.py create mode 100644 app/services/client_rate_service.py diff --git a/app/models/client_rate_model.py b/app/models/client_rate_model.py new file mode 100644 index 0000000..4ce334a --- /dev/null +++ b/app/models/client_rate_model.py @@ -0,0 +1,20 @@ +from app import db +from datetime import datetime + +class ClientRate(db.Model): + __tablename__ = "client_rates" + + id = db.Column(db.Integer, primary_key=True) + category = db.Column(db.String(50), nullable=False) + item_code = db.Column(db.String(50), nullable=False) + item_name = db.Column(db.String(200), nullable=False) + unit = db.Column(db.String(20)) + rate = db.Column(db.Numeric(12,2), nullable=False) + effective_from = db.Column(db.Date, nullable=False) + effective_to = db.Column(db.Date) + status = db.Column(db.String(20), default="Active") + created_at = db.Column(db.DateTime, default=datetime.now) + + def __repr__(self): + return f"< Client Rate {self.item_name}>" + \ No newline at end of file diff --git a/app/models/rate_model.py b/app/models/rate_model.py deleted file mode 100644 index e69de29..0000000 diff --git a/app/routes/engineering_master_routes.py b/app/routes/engineering_master_routes.py index 4a2fea5..ae41d73 100644 --- a/app/routes/engineering_master_routes.py +++ b/app/routes/engineering_master_routes.py @@ -6,10 +6,11 @@ from flask import ( url_for, flash, jsonify ) +from app.constants.messages import SuccessMessage, ErrorMessage from app.models.subcontractor_model import Subcontractor from app.services.subcontractor_rate_service import SubcontractorRateService -from app.constants.messages import SuccessMessage, ErrorMessage +from app.services.client_rate_service import ClientRateService engi_bp = Blueprint( "engineering", @@ -27,17 +28,60 @@ def engineering_master(): title="Engineering Masters" ) -# Client rate model -@engi_bp.route("/client-rate") -def client_rates(): +#---------------------- Client rate model ------------------------------- +@engi_bp.route("/client-rate", methods=["GET", "POST"]) +def client_rate_master(): + + if request.method == "POST": + result = ClientRateService.save_or_update(request.form) + if result["success"]: + flash(result["message"], "success") + return redirect(url_for("engineering.client_rate_master")) + else: + flash(result["message"], "danger") + + rates = ClientRateService.get_all_rates() return render_template( "engineering/client_rate.html", - title="Client Rate Master" + title="Client Rate Master", + rates=rates ) +@engi_bp.route("/client-rate/edit/", methods=["GET", "POST"]) +def client_edit_rate(rate_id): + + if request.method == "POST": + + result = ClientRateService.save_or_update(request.form) + + if result["success"]: + flash(result["message"], "success") + return redirect(url_for("engineering.client-rate")) + + flash(result["message"], "danger") + + rate = ClientRateService.get_rate(rate_id) + + rates = ClientRateService.get_all_rates() + + return render_template( + "engineering/client_rate.html", + rate=rate, + rates=rates + ) + +@engi_bp.route("/client-rate/delete/") +def client_delete_rate(rate_id): + ClientRateService.delete_rate(rate_id) + flash("Rate deleted successfully.", "success") + return redirect(url_for("engineering.client-rate")) + + + +# -------------------- Sub-Contractor ------------------------------------- @engi_bp.route("/subcontractor-rate", methods=["GET", "POST"]) -def add_subcontractor_rates(): +def subcontractor_rate_master(): subcontractors = Subcontractor.query.filter_by(status="Active").all() @@ -45,7 +89,7 @@ def add_subcontractor_rates(): result = SubcontractorRateService.save_or_update(request.form) if result["success"]: flash(result["message"], "success") - return redirect(url_for("engineering.add_subcontractor_rates")) + return redirect(url_for("engineering.subcontractor_rate_master")) else: flash(result["message"], "danger") @@ -59,7 +103,7 @@ def add_subcontractor_rates(): ) @engi_bp.route("/subcontractor-rate/edit/", methods=["GET", "POST"]) -def edit_rate(rate_id): +def subcontractor_edit_rate(rate_id): subcontractors = Subcontractor.query.filter_by(status="Active").all() @@ -69,7 +113,7 @@ def edit_rate(rate_id): if result["success"]: flash(result["message"], "success") - return redirect(url_for("engineering.add_subcontractor_rates")) + return redirect(url_for("engineering.subcontractor_rate_master")) flash(result["message"], "danger") @@ -85,10 +129,10 @@ def edit_rate(rate_id): ) @engi_bp.route("/subcontractor-rate/delete/") -def delete_rate(rate_id): +def subcontractor_delete_rate(rate_id): SubcontractorRateService.delete_rate(rate_id) flash("Rate deleted successfully.", "success") - return redirect(url_for("engineering.add_subcontractor_rates")) + return redirect(url_for("engineering.subcontractor_rate_master")) @engi_bp.route("/check-rate") diff --git a/app/services/client_rate_service.py b/app/services/client_rate_service.py new file mode 100644 index 0000000..f1c386d --- /dev/null +++ b/app/services/client_rate_service.py @@ -0,0 +1,97 @@ +from app.services.db_service import db +from app.models.client_rate_model import ClientRate +from sqlalchemy import func + + +class ClientRateService: + + @staticmethod + def save_or_update(form): + + rate_id = form.get("id") + category = form.get("category") + item_name = form.get("item_name").strip() + + # ----------------------------- + # Duplicate Validation + # ----------------------------- + duplicate = ( + ClientRate.query + .filter( + ClientRate.category == category, + func.lower(ClientRate.item_name) == item_name.lower() + ) + .first() + ) + + # Ignore current record while editing + if duplicate and (not rate_id or duplicate.id != int(rate_id)): + return { + "success": False, + "message": "Category and Rate already exists for this Client." + } + + # ----------------------------- + # Insert / Update + # ----------------------------- + if rate_id: + rate = ClientRate.query.get_or_404(rate_id) + else: + rate = ClientRate() + + rate.category = category + rate.item_code = form.get("item_code") + rate.item_name = item_name + rate.unit = form.get("unit") + rate.rate = form.get("rate") + rate.effective_from = form.get("effective_from") + rate.effective_to = form.get("effective_to") or None + rate.status = form.get("status") + + if not rate_id: + db.session.add(rate) + + db.session.commit() + + return { + "success": True, + "message": "Saved Successfully." + } + + @staticmethod + def get_all_rates(): + + return ( + ClientRate.query + .order_by(ClientRate.created_at.desc()) + .all() + ) + + + @staticmethod + def get_rate(rate_id): + + return ClientRate.query.get_or_404(rate_id) + + def delete_rate(rate_id): + rate = ClientRate.query.get_or_404(rate_id) + db.session.delete(rate) + db.session.commit() + + + @staticmethod + def check_duplicate(subcontractor_id, category, item_name, rate_id=None): + + query = ClientRate.query.filter( + ClientRate.category == category, + func.lower(ClientRate.item_name) == item_name.strip().lower() + ) + + if rate_id: + query = query.filter(ClientRate.id != int(rate_id)) + + return query.first() is not None + + + + \ No newline at end of file diff --git a/app/templates/engineering/client_rate.html b/app/templates/engineering/client_rate.html index a41a2b1..c2d09d9 100644 --- a/app/templates/engineering/client_rate.html +++ b/app/templates/engineering/client_rate.html @@ -14,7 +14,353 @@ +
+ +
+ + + + +
+ + +
+ + +
+ + +
+ + + +
+
+ +
+ + +
+ + +
+ + +
+ + + + +
+ + + +
+ + +
+ + +
+ + +
+
+ +
+
+ + +
+ +
+ + +
+
+ +
+ +
+ + Reset + + + +
+
+
+ +
+
+
+ Rate List +
+
+ +
+ + + + + + + + + + + + + + + + {% for row in rates %} + + + + + + + + + + + + {% endfor %} + + +
#CategoryItem CodeItem NameUnitRateStatusAction
{{ loop.index }}{{ row.category }}{{ row.item_code }}{{ row.item_name }}{{ row.unit }}{{ row.rate }} + {% if row.status=="Active" %} + + Active + + {% else %} + + Inactive + + {% endif %} + + + + + + + + +
+
+
+ + + {% endblock %} \ No newline at end of file diff --git a/app/templates/engineering/contractor_rate.html b/app/templates/engineering/contractor_rate.html index 5f892a9..1337c51 100644 --- a/app/templates/engineering/contractor_rate.html +++ b/app/templates/engineering/contractor_rate.html @@ -4,14 +4,12 @@
- +
-

Subcontractor Rate Master

-
@@ -67,23 +65,6 @@
- -
- - - -
@@ -95,7 +76,7 @@
-
+
+
+
+ + +
+ + +
+

- + Reset @@ -222,11 +222,11 @@ - + - diff --git a/app/templates/engineering/index.html b/app/templates/engineering/index.html index 1a4d4f8..23eac31 100644 --- a/app/templates/engineering/index.html +++ b/app/templates/engineering/index.html @@ -32,7 +32,7 @@ Manage subcontractor-wise rates.

- @@ -62,7 +62,7 @@ Manage client standard rates.

-
-- 2.49.1