metis-desk/modules/resources/src/api/infrastructure/persistence/resource-dashboard-reader.ts
2026-10-25 01:19:17 +02:00

63 lines
2.8 KiB
TypeScript

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<Entry>(
`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<Entry>(
"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 } }
);
}
}