import type { Sequelize } from "sequelize"; import { QueryTypes } from "sequelize"; type Entry = { eventId?: string; id: string; companyId: string; companyName: string; name: string; recordedAt: string | null; actorName: string | null; }; /** Consulta definiciones por stockKey, nunca por nombres editables. */ export class ResourceDashboardReader { constructor(private readonly database: Sequelize) {} stats(companyId?: string) { return this.database.query<{ companyId: string; count: number }>( "SELECT companyId,COUNT(*) AS count FROM resources WHERE companyId IS NOT NULL AND (:companyId IS NULL OR companyId=:companyId) GROUP BY companyId", { type: QueryTypes.SELECT, replacements: { companyId: companyId ?? null } } ); } async entries(companyId?: string, issue?: string, page = 1) { const expiry = issue === "certificate" || issue === "license"; const join = expiry ? " JOIN resource_definitions d ON d.id=r.templateId JOIN resource_definitions f ON f.stockKey='field:expires' JOIN resource_characteristics expiry ON expiry.resourceId=r.id AND expiry.fieldId=f.id" : ""; const where = "WHERE r.companyId IS NOT NULL AND (:companyId IS NULL OR r.companyId=:companyId)" + (expiry ? " AND d.stockKey=:stockKey AND r.active=1 AND expiry.dateValue BETWEEN :today AND :until" : ""); const today = new Date().toISOString().slice(0, 10); const until = new Date(Date.now() + 30 * 86400000).toISOString().slice(0, 10); const replacements = { companyId: companyId ?? null, stockKey: issue === "certificate" ? "template:certificate" : "template:software_license", today, until, offset: (page - 1) * 10, }; const counts = await this.database.query<{ total: number }>( `SELECT COUNT(*) AS total FROM resources r ${join} ${where}`, { type: QueryTypes.SELECT, replacements } ); const items = await this.database.query( `SELECT r.id,r.companyId,c.name AS companyName,r.name AS name,NULL AS recordedAt,NULL AS actorName FROM resources r JOIN companies c ON c.id=r.companyId ${join} ${where} ORDER BY name,r.id LIMIT 10 OFFSET :offset`, { type: QueryTypes.SELECT, replacements } ); return { total: Number(counts[0]?.total ?? 0), items }; } activity(companyId?: string) { return this.database.query( "SELECT r.id,h.id AS eventId,r.companyId,c.name AS companyName,r.name AS name,h.recordedAt,u.name AS actorName FROM resource_revisions h JOIN resources r ON r.id=h.resourceId JOIN companies c ON c.id=r.companyId LEFT JOIN users u ON u.id=h.actorId WHERE r.companyId IS NOT NULL AND (:companyId IS NULL OR r.companyId=:companyId) ORDER BY h.recordedAt DESC,h.id DESC LIMIT 6", { type: QueryTypes.SELECT, replacements: { companyId: companyId ?? null } } ); } }