feat(reports): reports module + /inicio + edo-cuenta-datos prefill
Build and Push Images / Build jorgecuadros-web (push) Successful in 1m35s
Build and Push Images / Build jorgecuadros-api (push) Successful in 2m11s

- New reports backend (registry, service, controller, outputs, types)
  with catalog endpoint + slug/CSV/XLSX/PDF/print outputs.
- /reportes catalog + /reportes/[slug] runner; ReportRunner + ContextReports
  components wire pre-filtered links from domain pages.
- Fix: /reportes/[slug] now reads searchParams and forwards initialParams to
  ReportRunner so /reportes/edo-cuenta-datos?customerId=... auto-runs
  instead of dropping the id and forcing a manual customer search.
- /inicio landing page; root + login redirect to /inicio.
- Company header env vars + logo asset for PDF/print rendering.
- exceljs + pdfkit deps.
This commit is contained in:
2026-07-23 23:20:41 -07:00
parent 921a47cbaa
commit 8802f08d4f
30 changed files with 4424 additions and 6 deletions
+36
View File
@@ -44,6 +44,8 @@ import type {
PropertyListResponse,
PropertySort,
PropertyStats,
ReportCatalog,
ReportRunResult,
ServiceInput,
TrustInput,
Role,
@@ -730,3 +732,37 @@ export function startOpsJob(kind: OpsJobKind, file?: string): Promise<OpsJob> {
body: JSON.stringify({ kind, file }),
});
}
/* ----------------------------------------------------------- Reports module */
export function getReportCatalog(): Promise<ReportCatalog> {
return apiFetch<ReportCatalog>("/reports");
}
export function runReport(
slug: string,
params: Record<string, string | undefined>,
): Promise<ReportRunResult> {
const qs = new URLSearchParams();
for (const [k, v] of Object.entries(params)) {
if (v != null && v !== "") qs.set(k, v);
}
const tail = qs.toString();
return apiFetch<ReportRunResult>(`/reports/${slug}${tail ? `?${tail}` : ""}`);
}
/** Build a download URL for a report's file output. The session cookie
* travels with the browser's same-origin navigation, so a plain `href`
* is enough — no fetch-with-credentials dance. */
export function reportDownloadUrl(
slug: string,
format: "csv" | "xlsx" | "pdf" | "print",
params: Record<string, string | undefined>,
): string {
const qs = new URLSearchParams();
for (const [k, v] of Object.entries(params)) {
if (v != null && v !== "") qs.set(k, v);
}
const tail = qs.toString();
return `${API_ORIGIN}/reports/${slug}/${format}${tail ? `?${tail}` : ""}`;
}
+55
View File
@@ -1025,3 +1025,58 @@ export interface BankSummary {
/** Cumulative figure the selected year opened on. */
opening: string;
}
/* ----------------------------------------------------------- Reports module */
export type ReportDomain =
| "clientes"
| "polizas"
| "servicios"
| "estado-cuenta"
| "chequera";
export type ReportFormat = "tabular" | "statement";
/** Param declaration a report exposes to its filter form. */
export type ReportParam =
| { key: string; label: string; kind: "text"; placeholder?: string; defaultValue?: string }
| { key: string; label: string; kind: "number"; defaultValue?: string }
| { key: string; label: string; kind: "date"; endOfDay?: boolean; defaultValue?: string }
| {
key: string;
label: string;
kind: "select";
options: { value: string; label: string }[];
defaultValue?: string;
}
| { key: string; label: string; kind: "customer-picker" };
export interface ReportColumn {
key: string;
label: string;
type: "text" | "number" | "money" | "date";
align?: "left" | "right";
width?: number;
}
export interface ReportDef {
slug: string;
title: string;
description: string;
domain: ReportDomain;
legacyName: string | null;
format: ReportFormat;
params: ReportParam[];
columns: ReportColumn[];
}
export interface ReportRunResult {
columns: ReportColumn[];
rows: Array<Record<string, unknown>>;
totals?: Record<string, string | number>;
subtitle?: string;
}
export interface ReportCatalog {
items: ReportDef[];
}