Metadata-Version: 2.4
Name: fiscalpy
Version: 0.0.18
Summary: Paquete para la limpieza, extracción y análisis de datos fiscales en Colombia
Author-email: Carlos Ortiz <cjortizb@javeriana.edu.co>
License-Expression: MIT
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pandas
Requires-Dist: numpy
Requires-Dist: openpyxl
Requires-Dist: sodapy
Requires-Dist: matplotlib
Dynamic: license-file

# FiscalPY

`fiscalpy` es un paquete de Python para facilitar la extracción, limpieza y análisis de datos fiscales y administrativos de Colombia.

Actualmente incluye herramientas para:

- limpiar datos del Presupuesto General de la Nación (PGN);
- limpiar y clasificar información de finanzas territoriales;
- descargar datos de `datos.gov.co` mediante la API de Socrata;
- generar reportes estandarizados de contratación pública a partir de datos de SECOP II.

## Instalación

```bash
pip install fiscalpy
```

Para trabajar con la versión local del repositorio durante el desarrollo:

```bash
pip install -e .
```

## ¿Cómo usarla?

### Presupuesto nacional

Para la limpieza del presupuesto nacional se cuenta con las funciones `limpieza_gastos_pgn` y `limpieza_ingresos_pgn`.

Los datos deben provenir directamente de los archivos publicados por el Ministerio de Hacienda y Crédito Público de Colombia, y la primera fila del archivo debe contener los nombres de las columnas.

```python
import pandas as pd
from fiscalpy import limpieza_gastos_pgn, limpieza_ingresos_pgn

gastos = pd.read_excel("gastos.xlsx")
rentas = pd.read_excel("rentas.xlsx")

gastos_limpios = limpieza_gastos_pgn(gastos)
rentas_limpias = limpieza_ingresos_pgn(rentas)
```

El resultado son `DataFrame` normalizados y preparados para análisis estadístico y gráfico.

### Finanzas territoriales

Para información territorial se incluyen las funciones:

- `limpieza_ingresos_territoriales`
- `limpieza_gastos_territoriales`
- `columnas_ingresos_territoriales`

Las dos primeras permiten normalizar datos de ingresos y gastos territoriales, tanto de ejecución como de programación.

```python
import pandas as pd
from fiscalpy import limpieza_ingresos_territoriales

df = pd.read_excel("datos_ejecucion_2025.xlsx")

norm_data = limpieza_ingresos_territoriales(
    df,
    tipo="ejecucion",
)
```

En el argumento `tipo` se debe indicar si se trabaja con datos de `"ejecucion"` o de `"programacion"`.

La función `columnas_ingresos_territoriales` agrega columnas de clasificación que permiten agrupar los ingresos territoriales con distintos niveles de detalle. Entre las agrupaciones disponibles se encuentran:

- recursos propios, transferencias y recursos de capital;
- ingresos tributarios, ingresos no tributarios, transferencias y recursos de capital;
- principales fuentes de ingreso relevantes para municipios y departamentos.

## Extracción de datos abiertos

### `datos_abiertos`

La función `datos_abiertos` descarga información directamente desde `datos.gov.co` utilizando la API de Socrata y devuelve el resultado como un `pandas.DataFrame`.

```python
from fiscalpy import datos_abiertos
```

La función recibe el identificador Socrata del conjunto de datos, un token de aplicación y, opcionalmente, filtros para limitar la consulta.

```python
from datetime import date
from fiscalpy import datos_abiertos

filtros = {
    "nit_entidad": {"in": ["900948953"]},
    "fecha_de_firma": {
        "gte": date(2022, 1, 1),
        "lt": date(2023, 1, 1),
    },
}

df = datos_abiertos(
    dataset_id="jbjy-vk9h",
    token="TU_TOKEN_SOCRATA",
    filtros=filtros,
)
```

En este ejemplo se consulta el dataset identificado por `jbjy-vk9h` y se conservan únicamente los registros que cumplen los filtros especificados.

#### Filtros simples

Para una igualdad se puede pasar directamente el valor:

```python
df = datos_abiertos(
    dataset_id="jbjy-vk9h",
    token="TU_TOKEN_SOCRATA",
    filtros={"estado_contrato": "En ejecución"},
)
```

Una lista se interpreta como una condición `IN`:

```python
filtros = {
    "estado_contrato": ["En ejecución", "Terminado"]
}
```

También es posible suministrar filtros simples como argumentos adicionales:

```python
df = datos_abiertos(
    "jbjy-vk9h",
    "TU_TOKEN_SOCRATA",
    nit_entidad="900948953",
)
```

#### Filtros avanzados

Los operadores disponibles son:

| Operador | Condición SoQL |
| --- | --- |
| `eq` | `=` |
| `ne` | `!=` |
| `gt` | `>` |
| `gte` | `>=` |
| `lt` | `<` |
| `lte` | `<=` |
| `in` | `IN (...)` |
| `not_in` | `NOT IN (...)` |
| `between` | `BETWEEN ... AND ...` |
| `not_between` | `NOT BETWEEN ... AND ...` |
| `like` | `LIKE` |
| `not_like` | `NOT LIKE` |
| `is_null` | `IS NULL` |
| `not_null` | `IS NOT NULL` |

Por ejemplo:

```python
filtros = {
    "valor_del_contrato": {"gte": 100_000_000},
    "fecha_de_firma": {
        "between": [date(2024, 1, 1), date(2024, 12, 31)]
    },
    "estado_contrato": {"not_in": ["Borrador"]},
}
```

La función pagina automáticamente las consultas en bloques de hasta 50.000 registros, por lo que puede descargar resultados que superen ese límite sin que el usuario tenga que manejar manualmente los `offset` de la API.

Para consultas frecuentes o de mayor tamaño se recomienda utilizar un token de aplicación de Socrata.

## Reportes

### `reporte_contratacion`

`reporte_contratacion` genera un reporte descriptivo de contratación pública a partir de un `DataFrame` de contratos y una tabla de IPC.

```python
from fiscalpy import reporte_contratacion
```

La función prepara los datos, expresa los valores monetarios en precios constantes, construye tablas de análisis y, opcionalmente, exporta un archivo Excel y gráficos en formato SVG.

Un flujo típico consiste en descargar primero los contratos con `datos_abiertos` y luego generar el reporte:

```python
import pandas as pd
from fiscalpy import datos_abiertos, reporte_contratacion

contratos = datos_abiertos(
    dataset_id="jbjy-vk9h",
    token="TU_TOKEN_SOCRATA",
    filtros={
        "nit_entidad": "900948953",
    },
)

ipc = pd.read_excel("datos_macro.xlsx")

resultado = reporte_contratacion(
    contratos,
    ipc,
    salida="salidas_contratacion",
    anio_base=2026,
    crecimiento_ipc_base=0.069,
    verbose=True,
)
```

### Datos requeridos

El `DataFrame` de contratación debe contener, como mínimo, las siguientes columnas:

```text
id_contrato
fecha_de_firma
valor_del_contrato
duraci_n_del_contrato
dias_adicionados
proveedor_adjudicado
tipo_de_contrato
modalidad_de_contratacion
estado_contrato
```

Estos nombres corresponden a la estructura utilizada por los datos de contratos electrónicos de SECOP II en `datos.gov.co`.

La tabla de IPC debe ser un `DataFrame` con las columnas:

```text
Año
IPC
```

Por ejemplo:

```python
ipc.head()
```

```text
    Año      IPC
0  2022   120.27
1  2023   131.35
2  2024   140.12
3  2025   152.27
```

### Año base y precios constantes

El argumento `anio_base` determina el año al que se llevan todos los valores monetarios.

```python
resultado = reporte_contratacion(
    contratos,
    ipc,
    salida="salidas_contratacion",
    anio_base=2026,
    crecimiento_ipc_base=0.069,
)
```

Si el IPC del año base ya se encuentra en la tabla de IPC, la función lo utiliza directamente. Si todavía no está disponible, `crecimiento_ipc_base` permite construirlo a partir del IPC del año inmediatamente anterior.

Por ejemplo, `0.069` representa un crecimiento de 6,9 %.

### Archivos generados

Por defecto se crea una estructura similar a:

```text
salidas_contratacion/
├── tablas_analisis_contratacion.xlsx
└── graficos_svg/
    ├── 01_contratos_anio.svg
    ├── 02_monto_anio.svg
    ├── 03_promedio_anio.svg
    ├── ...
    └── 15_dias_adicionados.svg
```

El archivo Excel contiene tablas sobre, entre otros temas:

- número y monto de contratos por año y mes;
- rangos de monto diario;
- monto diario ajustado por días adicionados;
- proveedores con mayores montos y mayor número de contratos;
- tipos y modalidades de contratación;
- estado de los contratos;
- distribución de días adicionados;
- contratos con montos diarios elevados;
- contratos con más de 100 días adicionados.

Los gráficos se exportan como SVG para conservar elementos vectoriales y texto editable. Si se requiere una copia en PNG, se puede utilizar:

```python
resultado = reporte_contratacion(
    contratos,
    ipc,
    salida="salidas_contratacion",
    exportar_png=True,
)
```

### Resultado en Python

Además de escribir archivos, la función devuelve un diccionario con los resultados del análisis:

```python
resultado.keys()
```

```text
dict_keys(['datos', 'ipc', 'tablas', 'graficos', 'excel', 'metadata'])
```

Los principales componentes son:

- `resultado["datos"]`: base de contratación preparada y enriquecida;
- `resultado["ipc"]`: tabla de IPC utilizada en el cálculo;
- `resultado["tablas"]`: diccionario con todas las tablas analíticas;
- `resultado["graficos"]`: rutas de los gráficos generados;
- `resultado["excel"]`: ruta del archivo Excel generado;
- `resultado["metadata"]`: información general del reporte.

Por ejemplo, las tablas pueden consultarse directamente sin abrir el Excel:

```python
resultado["tablas"]["resumen_general"]
resultado["tablas"]["por_anio"]
resultado["tablas"]["proveedores"]
resultado["tablas"]["contratos_mas_100_dias"]
```

### Opciones de exportación

La generación de archivos puede controlarse con los siguientes argumentos:

```python
resultado = reporte_contratacion(
    contratos,
    ipc,
    salida="salidas_contratacion",
    exportar_excel=True,
    exportar_graficos=True,
    exportar_png=False,
)
```

Esto permite utilizar `reporte_contratacion` tanto como generador de entregables como dentro de otros flujos de análisis en Python.

## Licencia

Este proyecto se distribuye bajo la licencia incluida en el repositorio.
