+server.js
5.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import { API_HOST } from '$lib/api.js';
const API_BASE = API_HOST + '/api/organismo';
let cachedClasificador = null;
let cachedEstados = null;
let cachedTimestamp = 0;
const CACHE_TTL = 5 * 60 * 1000;
// Organismo hierarchy: grupo → subgrupo → organismo
// Parent is derived from clasificador fields, not from code pattern
async function loadAndCacheAll() {
const now = Date.now();
if (cachedEstados && (now - cachedTimestamp) < CACHE_TTL) return;
const clasRes = await fetch(`${API_BASE}/clasificador`);
if (!clasRes.ok) throw new Error('Failed to fetch clasificador');
cachedClasificador = await clasRes.json();
const estados = new Map();
const batchSize = 80;
for (let i = 0; i < cachedClasificador.length; i += batchSize) {
const batch = cachedClasificador.slice(i, i + batchSize);
const results = await Promise.all(batch.map(async (item) => {
try {
const code = item.organismo;
const res = await fetch(`${API_BASE}/${code}`);
if (!res.ok) return null;
const data = await res.json();
return { code: String(code), estados: data.estados || [] };
} catch { return null; }
}));
results.filter(Boolean).forEach(r => estados.set(r.code, r.estados));
}
cachedEstados = estados;
cachedTimestamp = now;
}
export async function GET({ url }) {
const gestion = parseInt(url.searchParams.get('gestion') || '2025');
const entidad = url.searchParams.get('entidad') || '0';
try {
if (entidad === '0') {
await loadAndCacheAll();
const results = [];
const grupoSet = new Set();
const subgrupoSet = new Set();
for (const item of cachedClasificador) {
const code = String(item.organismo);
const estados = cachedEstados.get(code);
if (!estados) continue;
const yearData = estados.find(d => d.gestion === gestion);
if (!yearData || !yearData.total) continue;
const grupoKey = `g_${item.organismo_grupo}`;
const subgrupoKey = `sg_${item.organismo_grupo}_${item.organismo_subgrupo}`;
// Add grupo node if not yet added
if (!grupoSet.has(grupoKey)) {
grupoSet.add(grupoKey);
results.push({
gestion,
nivel: 'grupo',
organismo: grupoKey,
desc_organismo: item.desc_organismo_grupo || `Grupo ${item.organismo_grupo}`,
parent: null,
devengado: 0
});
}
// Add subgrupo node if not yet added
if (!subgrupoSet.has(subgrupoKey)) {
subgrupoSet.add(subgrupoKey);
results.push({
gestion,
nivel: 'subgrupo',
organismo: subgrupoKey,
desc_organismo: item.desc_organismo_subgrupo || `Subgrupo ${item.organismo_subgrupo}`,
parent: grupoKey,
devengado: 0
});
}
results.push({
gestion,
nivel: 'organismo',
organismo: code,
desc_organismo: item.desc_organismo || '',
parent: subgrupoKey,
devengado: yearData.total
});
}
return new Response(JSON.stringify(results), {
headers: { 'Content-Type': 'application/json' }
});
} else {
if (!cachedClasificador) {
const clasRes = await fetch(`${API_BASE}/clasificador`);
cachedClasificador = await clasRes.json();
}
const results = [];
const grupoSet2 = new Set();
const subgrupoSet2 = new Set();
const batchSize = 80;
for (let i = 0; i < cachedClasificador.length; i += batchSize) {
const batch = cachedClasificador.slice(i, i + batchSize);
const batchResults = await Promise.all(batch.map(async (item) => {
try {
const code = String(item.organismo);
const res = await fetch(`${API_BASE}/${code}/entidades/${entidad}`);
if (!res.ok) return null;
const data = await res.json();
const yearData = data.find(d => d.gestion === gestion);
if (!yearData || !yearData.monto) return null;
return { item, code, monto: yearData.monto };
} catch { return null; }
}));
batchResults.filter(Boolean).forEach(({ item, code, monto }) => {
const grupoKey = `g_${item.organismo_grupo}`;
const subgrupoKey = `sg_${item.organismo_grupo}_${item.organismo_subgrupo}`;
if (!grupoSet2.has(grupoKey)) {
grupoSet2.add(grupoKey);
results.push({ gestion, nivel: 'grupo', organismo: grupoKey, desc_organismo: item.desc_organismo_grupo || '', parent: null, devengado: 0 });
}
if (!subgrupoSet2.has(subgrupoKey)) {
subgrupoSet2.add(subgrupoKey);
results.push({ gestion, nivel: 'subgrupo', organismo: subgrupoKey, desc_organismo: item.desc_organismo_subgrupo || '', parent: grupoKey, devengado: 0 });
}
results.push({ gestion, nivel: 'organismo', organismo: code, desc_organismo: item.desc_organismo || '', parent: subgrupoKey, devengado: monto });
});
}
return new Response(JSON.stringify(results), {
headers: { 'Content-Type': 'application/json' }
});
}
} catch (err) {
return new Response(JSON.stringify({ error: 'Failed to build treemap' }), {
status: 500, headers: { 'Content-Type': 'application/json' }
});
}
}