v20260104-14-reports-stats-total-runs-success-rate-fix #28
@ -1 +1 @@
|
||||
v20260103-14-reports-percentage-2-decimals
|
||||
v20260103-15-reports-customer-column
|
||||
|
||||
@ -193,6 +193,7 @@ def build_report_columns_meta():
|
||||
"defaults": {
|
||||
"summary": [
|
||||
"object_name",
|
||||
"customer_name",
|
||||
"total_runs",
|
||||
"success_count",
|
||||
"warning_count",
|
||||
@ -238,7 +239,7 @@ def build_report_columns_meta():
|
||||
{"key": "job_id", "label": "Job ID", "views": ["snapshot"]},
|
||||
{"key": "backup_software", "label": "Job type", "views": ["snapshot"]},
|
||||
{"key": "backup_type", "label": "Repository / Target", "views": ["snapshot"]},
|
||||
{"key": "customer_name", "label": "Customer", "views": ["snapshot"]},
|
||||
{"key": "customer_name", "label": "Customer", "views": ["snapshot", "summary"]},
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -446,11 +447,14 @@ def api_reports_generate(report_id: int):
|
||||
text(
|
||||
'''
|
||||
INSERT INTO report_object_summaries
|
||||
(report_id, object_name, total_runs, success_count, success_override_count,
|
||||
(report_id, object_name, customer_id, customer_name,
|
||||
total_runs, success_count, success_override_count,
|
||||
warning_count, failed_count, missed_count, success_rate, created_at)
|
||||
SELECT
|
||||
:rid AS report_id,
|
||||
COALESCE(s.job_name, '(unknown job)') AS object_name,
|
||||
s.customer_id AS customer_id,
|
||||
s.customer_name AS customer_name,
|
||||
COUNT(*)::INTEGER AS total_runs,
|
||||
SUM(CASE WHEN (COALESCE(s.status,'') ILIKE 'success%' AND s.override_applied = FALSE) THEN 1 ELSE 0 END)::INTEGER AS success_count,
|
||||
SUM(CASE WHEN (s.override_applied = TRUE) THEN 1 ELSE 0 END)::INTEGER AS success_override_count,
|
||||
@ -469,7 +473,7 @@ def api_reports_generate(report_id: int):
|
||||
NOW() AS created_at
|
||||
FROM report_object_snapshots s
|
||||
WHERE s.report_id = :rid
|
||||
GROUP BY s.job_id, s.job_name
|
||||
GROUP BY s.customer_id, s.customer_name, s.job_id, s.job_name
|
||||
'''
|
||||
),
|
||||
{"rid": report_id},
|
||||
@ -513,7 +517,7 @@ def api_reports_data(report_id: int):
|
||||
q = db.session.query(ReportObjectSummary).filter(ReportObjectSummary.report_id == report_id)
|
||||
total = q.count()
|
||||
rows = (
|
||||
q.order_by(ReportObjectSummary.object_name.asc())
|
||||
q.order_by(db.func.coalesce(ReportObjectSummary.customer_name, '').asc(), ReportObjectSummary.object_name.asc())
|
||||
.offset(offset)
|
||||
.limit(limit)
|
||||
.all()
|
||||
@ -526,6 +530,8 @@ def api_reports_data(report_id: int):
|
||||
"items": [
|
||||
{
|
||||
"object_name": r.object_name or "",
|
||||
"customer_id": int(r.customer_id) if getattr(r, "customer_id", None) is not None else "",
|
||||
"customer_name": r.customer_name or "",
|
||||
"total_runs": int(r.total_runs or 0),
|
||||
"success_count": int(r.success_count or 0),
|
||||
"success_override_count": int(r.success_override_count or 0),
|
||||
@ -732,6 +738,8 @@ def api_reports_export_csv(report_id: int):
|
||||
if view == "summary":
|
||||
writer.writerow([
|
||||
"object_name",
|
||||
"customer_id",
|
||||
"customer_name",
|
||||
"total_runs",
|
||||
"success_count",
|
||||
"success_override_count",
|
||||
@ -743,12 +751,14 @@ def api_reports_export_csv(report_id: int):
|
||||
rows = (
|
||||
db.session.query(ReportObjectSummary)
|
||||
.filter(ReportObjectSummary.report_id == report_id)
|
||||
.order_by(ReportObjectSummary.object_name.asc())
|
||||
.order_by(db.func.coalesce(ReportObjectSummary.customer_name, '').asc(), ReportObjectSummary.object_name.asc())
|
||||
.all()
|
||||
)
|
||||
for r in rows:
|
||||
writer.writerow([
|
||||
r.object_name or "",
|
||||
r.customer_id or "",
|
||||
r.customer_name or "",
|
||||
int(r.total_runs or 0),
|
||||
int(r.success_count or 0),
|
||||
int(r.success_override_count or 0),
|
||||
|
||||
@ -1371,6 +1371,8 @@ def migrate_reporting_tables() -> None:
|
||||
id SERIAL PRIMARY KEY,
|
||||
report_id INTEGER NOT NULL REFERENCES report_definitions(id) ON DELETE CASCADE,
|
||||
object_name TEXT NOT NULL,
|
||||
customer_id INTEGER NULL,
|
||||
customer_name TEXT NULL,
|
||||
total_runs INTEGER NOT NULL DEFAULT 0,
|
||||
success_count INTEGER NOT NULL DEFAULT 0,
|
||||
success_override_count INTEGER NOT NULL DEFAULT 0,
|
||||
@ -1395,5 +1397,7 @@ def migrate_reporting_tables() -> None:
|
||||
conn.execute(text("ALTER TABLE report_definitions ADD COLUMN IF NOT EXISTS customer_scope VARCHAR(16) NOT NULL DEFAULT 'all'"))
|
||||
conn.execute(text("ALTER TABLE report_definitions ADD COLUMN IF NOT EXISTS customer_ids TEXT NULL"))
|
||||
conn.execute(text("ALTER TABLE report_object_snapshots ADD COLUMN IF NOT EXISTS customer_id INTEGER NULL"))
|
||||
conn.execute(text("ALTER TABLE report_object_summaries ADD COLUMN IF NOT EXISTS customer_id INTEGER NULL"))
|
||||
conn.execute(text("ALTER TABLE report_object_summaries ADD COLUMN IF NOT EXISTS customer_name TEXT NULL"))
|
||||
|
||||
print("[migrations] reporting tables created/verified.")
|
||||
|
||||
@ -612,6 +612,9 @@ class ReportObjectSummary(db.Model):
|
||||
report_id = db.Column(db.Integer, db.ForeignKey("report_definitions.id"), nullable=False)
|
||||
object_name = db.Column(db.Text, nullable=False)
|
||||
|
||||
customer_id = db.Column(db.Integer, nullable=True)
|
||||
customer_name = db.Column(db.Text, nullable=True)
|
||||
|
||||
total_runs = db.Column(db.Integer, nullable=False, default=0)
|
||||
success_count = db.Column(db.Integer, nullable=False, default=0)
|
||||
success_override_count = db.Column(db.Integer, nullable=False, default=0)
|
||||
|
||||
@ -128,6 +128,14 @@
|
||||
- CSV export generation
|
||||
- Improved readability and consistency of reported percentage values.
|
||||
|
||||
---
|
||||
|
||||
## v20260103-15-reports-customer-column
|
||||
|
||||
- Added **Customer** as a selectable column in report configuration.
|
||||
- Ensured customer name is included and visible when multiple customers are selected.
|
||||
- Updated summary and raw data views to correctly display customer information across multi-customer reports.
|
||||
|
||||
================================================================================================================================================
|
||||
|
||||
## v0.1.15
|
||||
|
||||
Loading…
Reference in New Issue
Block a user