Rafael Lopez

descagras

......@@ -102,14 +102,7 @@
codigo = String(meta.municipio_ubigeo || '');
tipo = 'ubigeo';
} else if (isClass && cls === 'acteco') {
const s = meta.acteco_sector != null ? String(Math.round(meta.acteco_sector)) : '';
if (s) {
codigo = s;
if (meta.acteco_subsector != null) {
codigo += '.' + Math.round(meta.acteco_subsector);
if (meta.acteco_actividad != null) codigo += '.' + Math.round(meta.acteco_actividad);
}
}
codigo = meta.acteco_actividad_armonizado || meta.acteco_subsector_armonizado || meta.acteco_sector_armonizado || '';
tipo = 'acteco';
} else if (!isClass) {
// Programa/proyecto
......
......@@ -796,10 +796,7 @@
} else if (isFinfunClass) {
url = `/finfun/${getFinfunCodigo(meta)}`;
} else if (hit.document.class_ === 'acteco') {
const s = String(meta.acteco_sector ? Math.round(meta.acteco_sector) : '');
let code = s;
if (meta.acteco_actividad !== undefined && meta.acteco_subsector !== undefined) code = `${s}.${Math.round(meta.acteco_subsector)}.${Math.round(meta.acteco_actividad)}`;
else if (meta.acteco_subsector !== undefined) code = `${s}.${Math.round(meta.acteco_subsector)}`;
const code = meta.acteco_actividad_armonizado || meta.acteco_subsector_armonizado || meta.acteco_sector_armonizado || '';
url = `/acteco/${code}`;
} else if (hit.document.class_ === 'rubro') {
const code = meta.rubro_sub_cuenta || meta.rubro_cuenta || meta.rubro_clase || meta.rubro_tipo || '';
......@@ -1438,7 +1435,7 @@
{@const isOrganismoClass = hit.document.class_ === 'organismo'}
{@const isClassResult = hit.document.is_class === true}
{@const hitType = CLASS_REVERSE_MAP[hit.document.class_] || hit.document.class_}
{@const actecoCode = isActecoClass ? (() => { const s = String(meta.acteco_sector ? Math.round(meta.acteco_sector) : ''); if (meta.acteco_actividad !== undefined && meta.acteco_subsector !== undefined) return `${s}.${Math.round(meta.acteco_subsector)}.${Math.round(meta.acteco_actividad)}`; if (meta.acteco_subsector !== undefined) return `${s}.${Math.round(meta.acteco_subsector)}`; return s; })() : ''}
{@const actecoCode = isActecoClass ? (meta.acteco_actividad_armonizado || meta.acteco_subsector_armonizado || meta.acteco_sector_armonizado || '') : ''}
{@const rubroCode = isRubroClass ? (meta.rubro_sub_cuenta || meta.rubro_cuenta || meta.rubro_clase || meta.rubro_tipo || '') : ''}
<a
href={isEntidadClass
......
......@@ -42,15 +42,8 @@
const doc = hit.document || {};
let meta = {};
try { meta = typeof doc.metadatos === 'string' ? JSON.parse(doc.metadatos) : (doc.metadatos || {}); } catch {}
const s = meta.acteco_sector != null ? String(Math.round(meta.acteco_sector)) : '';
if (!s) return null;
let code = s;
if (meta.acteco_subsector != null) {
code += '.' + Math.round(meta.acteco_subsector);
if (meta.acteco_actividad != null) {
code += '.' + Math.round(meta.acteco_actividad);
}
}
const code = meta.acteco_actividad_armonizado || meta.acteco_subsector_armonizado || meta.acteco_sector_armonizado || '';
if (!code) return null;
return { code, label: doc.texto || '' };
}).filter(Boolean);
} catch {
......
import { API_HOST } from '$lib/api.js';
const API_BASE = API_HOST + '/api/ubigeo/todo';
export async function GET({ url }) {
const gestion = url.searchParams.get('gestion') || '';
const apiUrl = new URL(API_BASE);
if (gestion) apiUrl.searchParams.set('gestion', gestion);
try {
const response = await fetch(apiUrl.toString());
if (!response.ok) {
return new Response(JSON.stringify({ error: `API error: ${response.status}` }), {
status: response.status, headers: { 'Content-Type': 'application/json' }
});
}
const data = await response.json();
return new Response(JSON.stringify(data), {
headers: { 'Content-Type': 'application/json' }
});
} catch {
return new Response(JSON.stringify({ error: 'Failed to fetch' }), {
status: 500, headers: { 'Content-Type': 'application/json' }
});
}
}
......@@ -96,7 +96,7 @@
<!-- Completo -->
<div class="section">
<h2 class="section-title">Completo</h2>
<a href={buildUrl('completo', 'ultimo')} class="download-link">
<a href={buildUrl('completo', 'ultimo')} download rel="external" class="download-link">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
Descargar todo ({dataset === 'gasto' ? 'gastos' : 'ingresos'})
</a>
......@@ -107,7 +107,7 @@
<h2 class="section-title">Por gestión</h2>
<div class="year-grid">
{#each YEARS as year}
<a href={buildUrl('gestion', year)} class="year-link">{year}</a>
<a href={buildUrl('gestion', year)} download rel="external" class="year-link">{year}</a>
{/each}
</div>
</div>
......@@ -155,7 +155,7 @@
{#if selectedEntity}
<div class="entity-result">
<span class="entity-name">{selectedEntity.desc_entidad}</span>
<a href={buildUrl('entidad', selectedEntity.entidad)} class="download-link">
<a href={buildUrl('entidad', selectedEntity.entidad)} download rel="external" class="download-link">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
Descargar
</a>
......
export const ssr = false;
export async function load({ fetch }) {
const pobRes = await fetch('/poblacion.csv').then(r => r.text());
const [pobRes, ubigeoRes] = await Promise.all([
fetch('/poblacion.csv').then(r => r.text()),
fetch('/api/ubigeo-todo?gestion=2025').then(r => r.json())
]);
const poblacionMap = {};
pobRes.split('\n').slice(1).forEach(line => {
......@@ -11,10 +14,22 @@ export async function load({ fetch }) {
}
});
const resumen = (ubigeoRes || [])
.filter(d => d.ubigeo !== '0.0.0' && !d.ubigeo.endsWith('.0') && !/multimunicipal/i.test(d.desc_ubigeo) && !/multiprovincial/i.test(d.desc_ubigeo) && !/desconocido/i.test(d.desc_ubigeo))
.map(d => ({
codigo: d.ubigeo,
desc: d.desc_ubigeo,
gestion: d.gestion,
devengado: d.monto,
ranking: d.ranking,
per_capita: d.per_capita,
departamento: d.desc_departamento
}));
const gestiones = [2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025];
return {
resumen: [],
resumen,
poblacionMap,
gestiones,
gestionInicial: 2025
......
......@@ -66,10 +66,7 @@
return fin;
}},
acteco: { class_: 'acteco', codigoFn: (meta) => {
const s = String(meta.acteco_sector ? Math.round(meta.acteco_sector) : '');
if (meta.acteco_actividad !== undefined) return `${s}.${Math.round(meta.acteco_subsector)}.${Math.round(meta.acteco_actividad)}`;
if (meta.acteco_subsector !== undefined) return `${s}.${Math.round(meta.acteco_subsector)}`;
return s;
return meta.acteco_actividad_armonizado || meta.acteco_subsector_armonizado || meta.acteco_sector_armonizado || '';
}},
};
......@@ -204,12 +201,7 @@
const map = {};
const esClasificador = clasificadorSeleccionado !== 'total' && clasSeleccionado;
resumen.forEach(d => {
let val;
if (modoPerCapita) {
val = esClasificador ? (d.per_capita || 0) : (poblacionMap[d.codigo] ? d.devengado / poblacionMap[d.codigo] : d.devengado);
} else {
val = d.devengado;
}
const val = modoPerCapita ? (d.per_capita || 0) : d.devengado;
map[d.codigo] = { ...d, valor: val };
});
return map;
......@@ -378,9 +370,31 @@
return;
}
// Modo total: datos no disponibles sin Supabase
// TODO: implementar endpoint API para resumen por municipio
// Modo total: cargar gasto agregado por municipio
const key = `total_${gestion}`;
if (resumenCache[key]) {
resumen = resumenCache[key];
} else {
try {
const res = await fetch(`/api/ubigeo-todo?gestion=${gestion}`);
const data = await res.json();
const mapped = (data || [])
.filter(d => d.ubigeo !== '0.0.0' && !d.ubigeo.endsWith('.0') && !/multimunicipal/i.test(d.desc_ubigeo) && !/multiprovincial/i.test(d.desc_ubigeo) && !/desconocido/i.test(d.desc_ubigeo))
.map(d => ({
codigo: d.ubigeo,
desc: d.desc_ubigeo,
gestion: d.gestion,
devengado: d.monto,
ranking: d.ranking,
per_capita: d.per_capita,
departamento: d.desc_departamento
}));
resumenCache[key] = mapped;
resumen = mapped;
} catch {
resumen = [];
}
}
poblacionMap = await getPoblacionAno(gestion);
}
......@@ -668,7 +682,7 @@
<path d={pathGen(mapaData.bolivia)} class="mapa-pais-fill" />
<path d={pathGen(mapaData.bolivia)} class="mapa-pais-outline" />
{#each mapaData.municipios.features as feat}
{@const cod = clasificadorSeleccionado !== 'total' ? feat.properties.ubigeo : String(feat.properties.codigo)}
{@const cod = feat.properties.ubigeo}
{@const datos = datosPorCodigo[cod]}
{@const visible = enRango(cod)}
{@const color = datos && visible ? colorScale(datos.valor) : 'transparent'}
......