fix(dashboard): align inventory and act follow-up metrics

This commit is contained in:
2026-09-08 18:07:17 -03:00
parent 11052c83aa
commit 79258836b1
+46 -10
View File
@@ -1,7 +1,7 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { DataSource } from 'typeorm'; import { DataSource } from 'typeorm';
export interface DashboardAuditItem { export interface DashboardInspectorActivityItem {
id: string; id: string;
occurredAt: Date; occurredAt: Date;
actorUsername: string | null; actorUsername: string | null;
@@ -19,6 +19,7 @@ interface DashboardCountsRow {
inactiveUsers: number | string; inactiveUsers: number | string;
activeSessions: number | string; activeSessions: number | string;
openFindings: number | string; openFindings: number | string;
actsInFollowUp: number | string;
findingsWithoutControlDate: number | string; findingsWithoutControlDate: number | string;
overdueControls: number | string; overdueControls: number | string;
controlsNext30Days: number | string; controlsNext30Days: number | string;
@@ -49,9 +50,14 @@ export class DashboardService {
return this.dataSource.transaction('REPEATABLE READ', async (manager) => { return this.dataSource.transaction('REPEATABLE READ', async (manager) => {
const [counts] = (await manager.query(` const [counts] = (await manager.query(`
SELECT SELECT
(SELECT COUNT(*) FROM assets WHERE information_status <> 'INACTIVE') AS "totalAssets", (SELECT COUNT(*) FROM assets WHERE is_inventory_instance=true AND information_status <> 'INACTIVE') AS "totalAssets",
(SELECT COUNT(*) FROM assets WHERE information_status NOT IN ('VALIDATED','INACTIVE')) AS "assetsNeedValidation", (SELECT COUNT(*) FROM assets WHERE is_inventory_instance=true AND information_status NOT IN ('VALIDATED','INACTIVE')) AS "assetsNeedValidation",
(SELECT COUNT(*) FROM assets asset WHERE asset.information_status <> 'INACTIVE' AND NOT EXISTS (SELECT 1 FROM asset_geometries geometry WHERE geometry.asset_id=asset.id)) AS "assetsWithoutGeometry", (
SELECT COUNT(*) FROM assets asset
WHERE asset.is_inventory_instance=true
AND asset.information_status <> 'INACTIVE'
AND NOT EXISTS (SELECT 1 FROM asset_geometries geometry WHERE geometry.asset_id=asset.id)
) AS "assetsWithoutGeometry",
(SELECT COUNT(*) FROM inspection_visits WHERE status='PLANNED') AS "plannedInspections", (SELECT COUNT(*) FROM inspection_visits WHERE status='PLANNED') AS "plannedInspections",
(SELECT COUNT(*) FROM users WHERE status = 'ACTIVE') AS "activeUsers", (SELECT COUNT(*) FROM users WHERE status = 'ACTIVE') AS "activeUsers",
(SELECT COUNT(*) FROM users WHERE status = 'INACTIVE') AS "inactiveUsers", (SELECT COUNT(*) FROM users WHERE status = 'INACTIVE') AS "inactiveUsers",
@@ -61,9 +67,22 @@ export class DashboardService {
WHERE revoked_at IS NULL WHERE revoked_at IS NULL
AND expires_at > CURRENT_TIMESTAMP AND expires_at > CURRENT_TIMESTAMP
) AS "activeSessions", ) AS "activeSessions",
(SELECT COUNT(*) FROM inspection_findings WHERE status = 'OPEN') AS "openFindings",
( (
SELECT COUNT(*) FROM inspection_findings WHERE status = 'OPEN' SELECT COUNT(*)
) AS "openFindings", FROM inspection_acts act
WHERE act.status IN ('SEALED','CLOSED','RECTIFIED')
AND NOT (
EXISTS (
SELECT 1 FROM inspection_findings finding
WHERE finding.act_id=act.id AND finding.status<>'VOIDED'
)
AND NOT EXISTS (
SELECT 1 FROM inspection_findings finding
WHERE finding.act_id=act.id AND finding.status='OPEN'
)
)
) AS "actsInFollowUp",
( (
SELECT COUNT(*) SELECT COUNT(*)
FROM inspection_findings finding FROM inspection_findings finding
@@ -115,7 +134,7 @@ export class DashboardService {
) AS "sealedActsWithoutReport" ) AS "sealedActsWithoutReport"
`)) as DashboardCountsRow[]; `)) as DashboardCountsRow[];
const recentAudit = (await manager.query(` const recentInspectorActivity = (await manager.query(`
SELECT SELECT
event.id, event.id,
event.occurred_at AS "occurredAt", event.occurred_at AS "occurredAt",
@@ -124,9 +143,25 @@ export class DashboardService {
event.entity_type AS "entityType", event.entity_type AS "entityType",
event.entity_id AS "entityId" event.entity_id AS "entityId"
FROM audit_events event FROM audit_events event
WHERE event.actor_user_id IS NOT NULL
AND (
EXISTS (
SELECT 1 FROM inspection_visit_members member
WHERE member.user_id=event.actor_user_id AND member.included=true
)
OR EXISTS (
SELECT 1 FROM inspection_visits visit
WHERE visit.lead_inspector_user_id=event.actor_user_id
)
)
AND (
event.action LIKE 'INSPECTION_%'
OR event.action LIKE 'ASSET_%'
OR event.action LIKE 'FINDING_%'
)
ORDER BY event.occurred_at DESC, event.id DESC ORDER BY event.occurred_at DESC, event.id DESC
LIMIT 6 LIMIT 8
`)) as DashboardAuditItem[]; `)) as DashboardInspectorActivityItem[];
const upcomingControls = (await manager.query(` const upcomingControls = (await manager.query(`
SELECT SELECT
@@ -168,6 +203,7 @@ export class DashboardService {
inactiveUsers: Number(counts?.inactiveUsers ?? 0), inactiveUsers: Number(counts?.inactiveUsers ?? 0),
activeSessions: Number(counts?.activeSessions ?? 0), activeSessions: Number(counts?.activeSessions ?? 0),
openFindings: Number(counts?.openFindings ?? 0), openFindings: Number(counts?.openFindings ?? 0),
actsInFollowUp: Number(counts?.actsInFollowUp ?? 0),
findingsWithoutControlDate: Number(counts?.findingsWithoutControlDate ?? 0), findingsWithoutControlDate: Number(counts?.findingsWithoutControlDate ?? 0),
overdueControls: Number(counts?.overdueControls ?? 0), overdueControls: Number(counts?.overdueControls ?? 0),
controlsNext30Days: Number(counts?.controlsNext30Days ?? 0), controlsNext30Days: Number(counts?.controlsNext30Days ?? 0),
@@ -175,7 +211,7 @@ export class DashboardService {
reportsOfficialized: Number(counts?.reportsOfficialized ?? 0), reportsOfficialized: Number(counts?.reportsOfficialized ?? 0),
sealedActsWithoutReport: Number(counts?.sealedActsWithoutReport ?? 0), sealedActsWithoutReport: Number(counts?.sealedActsWithoutReport ?? 0),
}, },
recentAudit, recentInspectorActivity,
upcomingControls, upcomingControls,
generatedAt: new Date().toISOString(), generatedAt: new Date().toISOString(),
}; };