diff --git a/app/billing/emails.py b/app/billing/emails.py index 7476fc3..b0bfeb8 100644 --- a/app/billing/emails.py +++ b/app/billing/emails.py @@ -8,6 +8,7 @@ app/templates/billing/email/. import logging import threading +from urllib.parse import urlparse from flask import current_app, render_template from flask_mail import Message from app import mail @@ -91,6 +92,13 @@ def send_billing_email(to_addr: str, event_type: str, context_dict: dict): app = current_app._get_current_object() + # Derive noreply sender from APP_BASE_URL so billing emails match the tenant domain. + try: + _netloc = urlparse(app.config.get('APP_BASE_URL', '')).netloc + _sender = f'noreply@{_netloc}' if _netloc else app.config.get('MAIL_DEFAULT_SENDER', '') + except Exception: + _sender = app.config.get('MAIL_DEFAULT_SENDER', '') + def _send(): try: with app.app_context(): @@ -105,6 +113,7 @@ def send_billing_email(to_addr: str, event_type: str, context_dict: dict): msg = Message( subject=subject, recipients=[to_addr], + sender=_sender or None, body=plain_body, html=html_body, ) diff --git a/app/routes/reports.py b/app/routes/reports.py index c327d0e..a06752b 100644 --- a/app/routes/reports.py +++ b/app/routes/reports.py @@ -12,6 +12,7 @@ from app import db from app.models.inspection import Inspection, InspectionTemplate from app.models.facility import Facility, Area from app.models.issue import Issue +from app.models.project import Project from app.models.user import User from app.utils.decorators import supervisor_required from app.utils.scope import get_customer_scope @@ -1105,8 +1106,13 @@ def issues_aging(): if customer_facility_ids is not None: facilities = (Facility.query.filter(Facility.id.in_(customer_facility_ids), Facility.active == True) .order_by(Facility.name).all()) if customer_facility_ids else [] + projects = (Project.query + .join(Facility, Project.id == Facility.project_id) + .filter(Facility.id.in_(customer_facility_ids), Project.active == True) + .distinct().order_by(Project.name).all()) if customer_facility_ids else [] else: facilities = Facility.query.filter_by(active=True).order_by(Facility.name).all() + projects = Project.query.filter_by(active=True).order_by(Project.name).all() return render_template('reports/issues_aging.html', now=now, @@ -1118,6 +1124,7 @@ def issues_aging(): severity_filter=severity_filter, facility_id_filter=facility_id_filter, facilities=facilities, + projects=projects, ) @@ -1282,8 +1289,13 @@ def sla_compliance(): if customer_facility_ids is not None: facilities = (Facility.query.filter(Facility.id.in_(customer_facility_ids), Facility.active == True) .order_by(Facility.name).all()) if customer_facility_ids else [] + projects = (Project.query + .join(Facility, Project.id == Facility.project_id) + .filter(Facility.id.in_(customer_facility_ids), Project.active == True) + .distinct().order_by(Project.name).all()) if customer_facility_ids else [] else: facilities = Facility.query.filter_by(active=True).order_by(Facility.name).all() + projects = Project.query.filter_by(active=True).order_by(Project.name).all() return render_template('reports/sla_compliance.html', start=start, end=end, @@ -1292,6 +1304,7 @@ def sla_compliance(): by_facility=by_facility, facility_id_filter=facility_id_filter, facilities=facilities, + projects=projects, ) diff --git a/app/templates/reports/issues_aging.html b/app/templates/reports/issues_aging.html index d654a1b..afd50a2 100644 --- a/app/templates/reports/issues_aging.html +++ b/app/templates/reports/issues_aging.html @@ -29,9 +29,20 @@ {% endfor %} -
+ {% if projects %} +
+ + +
+ {% endif %} +
- {% for f in facilities %} @@ -46,6 +57,36 @@
+{% if projects %} + +{% endif %} + {# ── KPI row ── #}
diff --git a/app/templates/reports/sla_compliance.html b/app/templates/reports/sla_compliance.html index 186850d..8ac963d 100644 --- a/app/templates/reports/sla_compliance.html +++ b/app/templates/reports/sla_compliance.html @@ -25,17 +25,28 @@
-
+
-
+
-
+ {% if projects %} +
+ + +
+ {% endif %} +
- {% for f in facilities %} @@ -50,6 +61,36 @@
+{% if projects %} + +{% endif %} + {% if total == 0 %}
No resolved issues found for this period and filter.