Saltar al contenido principal

Paquete de código abierto · LCSP y Reglamento de IA

Código descargable bajo licencia MIT.

Nueve archivos (cinco herramientas normativas y cuatro clientes de datos abiertos) en la intersección del derecho público español, la regulación europea de IA y las fuentes oficiales. Cada uno implementa un precepto concreto, verificable línea a línea. Descarga directa, sin registro ni rastreadores.

~162 KB totalLicencia MITStdlib + 2 deps (solo en el generador)

Modos de uso

CLI, módulo o cron, según el flujo de trabajo.

En un equipo local

Se descarga el archivo y se ejecuta con node o python. Cada script viene con CLI y argumentos posicionales.

Dentro de una aplicación

Se importa la función exportada (analizarOfertas, generateWithDisclosure) y se integra en la lógica de negocio. Sin acoplamiento al framework.

En cron

placsp-fetcher.py y los scripts de análisis se ejecutan sin modificaciones en GitHub Actions, cron Linux o Vercel Cron. Sin instalación.

Cinco herramientas normativas · descarga directa

Archivos por norma implementada.

Vista previa de las primeras líneas para revisar el estilo antes de descargar. El archivo completo incluye documentación, CLI y ejemplos de uso.

baja-temeraria.js

JavaScript

art. 85 RGLCAP · RD 1098/2001

Implementación de los supuestos del art. 85 RGLCAP para identificar ofertas incursas en presunción de anormalidad: exclusión de la oferta más elevada y último inciso del apartado 3, nueva media del apartado 4 y reducción del apartado 5. Es el módulo que ejecuta la calculadora en línea. Sin dependencias. Funciona en Node.js 22 y en navegadores actuales. Incluye CLI.

/**
 * baja-temeraria.js
 *
 * Identificación de ofertas incursas en presunción de anormalidad conforme al
 * artículo 85 del Real Decreto 1098/2001 (Reglamento General de la Ley de
 * Contratos de las Administraciones Públicas, RGLCAP).
 *
 * Supuestos según el número de licitadores:
 *   1 licitador   → inferior al presupuesto base en más de 25 unidades (art. 85.1).
 *   2 licitadores → la inferior en más de 20 unidades a la otra oferta (art. 85.2).
 *   3 licitadores → inferiores en más de 10 unidades a la media. La oferta más
 *                   elevada se excluye del cómputo de la media si la supera en
 *                   más de 10 unidades. En cualquier caso, baja superior a 25
 *                   unidades sobre el presupuesto base (art. 85.3).
 *   4 o más       → inferiores en más de 10 unidades a la media. Si hay ofertas
 *                   superiores a la media en más de 10 unidades, se calcula una
 *                   nueva media sin ellas; si quedan menos de tres ofertas, sobre
 *                   las tres de menor cuantía (art. 85.4).
 *
 * Criterios de cálculo:
 *   · Las unidades porcentuales se aplican sobre la media de los importes y no
 *     sobre la media de las bajas (JCCA, Informe 47/03).
 *   · El último inciso del art. 85.3 se refiere al presupuesto base de licitación
 *     (TACRC, Resoluciones 946/2023 y 1020/2017).
 *   · El pliego puede reducir los porcentajes en un tercio (art. 85.5): opción
 *     reducirUnTercio.
 *   · Empresas de un mismo grupo: se introduce solo la oferta más baja (art. 149.3
 *     LCSP y art. 86.1 RGLCAP).
 *   · Presupuesto base y ofertas deben expresarse en la misma base (sin IVA).
 *
 * El resultado es una presunción: la oferta solo puede excluirse tras el
 * procedimiento del art. 149 LCSP.
 *
 * Sin dependencias externas. Node.js 22 o navegador moderno.
 *
 * Autor:       LloretIA (https://lloretia.com)
 * Licencia:    MIT
 * Versión:     2.0.0 (noviembre de 2026: corrige los apartados 3 y 4)
 * Normativa:   RD 1098/2001 arts. 85 y 86 · Ley 9/2017 art. 149
 */

export function analizarOfertas(presupuestoBase, ofertas, opciones = {}) {
  // Archivo completo en la descarga.
}

Uso CLI

$ node baja-temeraria.js 100000 95000 90000 88000 85000 50000

baja-temeraria.py

Python 3.10+

art. 85 RGLCAP · RD 1098/2001

Equivalente en Python del módulo JavaScript anterior, con el mismo algoritmo y los mismos campos de resultado. Admite su integración en procesos de análisis de licitaciones. Utiliza únicamente la biblioteca estándar.

"""
baja-temeraria.py

Identificación de ofertas incursas en presunción de anormalidad conforme al
artículo 85 del Real Decreto 1098/2001 (Reglamento General de la Ley de
Contratos de las Administraciones Públicas, RGLCAP).

Supuestos según el número de licitadores:
  1 licitador   → inferior al presupuesto base en más de 25 unidades (art. 85.1).
  2 licitadores → la inferior en más de 20 unidades a la otra oferta (art. 85.2).
  3 licitadores → inferiores en más de 10 unidades a la media. La oferta más
                  elevada se excluye del cómputo de la media si la supera en
                  más de 10 unidades. En cualquier caso, baja superior a 25
                  unidades sobre el presupuesto base (art. 85.3).
  4 o más       → inferiores en más de 10 unidades a la media. Si hay ofertas
                  superiores a la media en más de 10 unidades, se calcula una
                  nueva media sin ellas; si quedan menos de tres ofertas, sobre
                  las tres de menor cuantía (art. 85.4).

Criterios de cálculo:
  · Las unidades porcentuales se aplican sobre la media de los importes y no
    sobre la media de las bajas (JCCA, Informe 47/03).
  · El último inciso del art. 85.3 se refiere al presupuesto base de licitación
    (TACRC, Resoluciones 946/2023 y 1020/2017).
  · El pliego puede reducir los porcentajes en un tercio (art. 85.5): parámetro
    reducir_un_tercio.
  · Empresas de un mismo grupo: se introduce solo la oferta más baja (art. 149.3
    LCSP y art. 86.1 RGLCAP).
  · Presupuesto base y ofertas deben expresarse en la misma base (sin IVA).

El resultado es una presunción: la oferta solo puede excluirse tras el
procedimiento del art. 149 LCSP.

Equivalente Python de baja-temeraria.js: mismo algoritmo y mismos campos de
resultado. Solo biblioteca estándar.

Autor:       LloretIA (https://lloretia.com)
Licencia:    MIT
Versión:     2.0.0 (noviembre de 2026: corrige los apartados 3 y 4)
Normativa:   RD 1098/2001 arts. 85 y 86 · Ley 9/2017 art. 149
Python:      3.10+
"""

def analizar_ofertas(presupuesto_base: float, ofertas: list[float], reducir_un_tercio: bool = False) -> Resultado:
    # Archivo completo en la descarga.
    ...

Uso CLI

$ python baja-temeraria.py 100000 95000 90000 88000 85000 50000

eu-ai-act-watermark.ts

TypeScript

art. 50 Reg. (UE) 2024/1689 · EU AI Act

Capa técnica de cumplimiento del art. 50 EU AI Act (aplicable desde el 2 de agosto de 2026; el marcado del apdo. 2 tiene un transitorio hasta el 2 de diciembre de 2026 para sistemas ya comercializados): marcado machine-readable del contenido generado por IA (SHA-256 + metadata), aviso visible localizado (es/en/ca) y wrapper para envolver llamadas a LLM. Diseñado para asistentes ciudadanos de AAPP.

/**
 * eu-ai-act-watermark.ts
 *
 * Capa de cumplimiento del artículo 50 del Reglamento (UE) 2024/1689
 * (EU AI Act). Marcado técnico machine-readable + disclosure visible.
 *
 * Cobertura:
 *   · art. 50.1 — info a personas físicas sobre interacción con IA
 *   · art. 50.2 — marcado técnico del output sintético
 *   · art. 50.4 — disclosure visible para contenido informativo público
 *
 * Stack: TypeScript (Node 18+ / Web Crypto API). Sin dependencias.
 */

export interface SyntheticMetadata {
  content: string;
  modelId: string;
  generatedAt: string;
  providerId: string;
  contentHash: string;       // SHA-256
  language: 'es' | 'en' | 'ca';
  auditId?: string;
}

export async function generateWithDisclosure(
  generator: () => Promise<string>,
  options: { modelId: string; providerId: string; language?: 'es'|'en'|'ca' }
): Promise<{ content: string; disclosure: string; metadata: SyntheticMetadata }> {
  const content = await generator();
  const metadata = await markAsSynthetic(content, options);
  const disclosure = buildDisclosure(metadata);
  return { content, disclosure, metadata };
}

placsp-fetcher.py

Python 3.10+

PLACSP · feed Atom oficial

Cliente del feed Atom público del PLACSP con filtros por CPV (Common Procurement Vocabulary), palabras clave e importe. Sin dependencias externas: se ejecuta en GitHub Actions, cron de Linux o Vercel Cron. Aplicable a vigilancia interna de la propia entidad sobre publicaciones, detección de patrones en pliegos y observatorios sectoriales de contratación.

"""
placsp_fetcher.py — Detector de licitaciones del PLACSP via Atom feed.

Filtros soportados:
  · CPV (códigos del Common Procurement Vocabulary)
  · Palabras clave (subcadena en título / resumen)
  · Importe mínimo / máximo (€)

Standard library only — corre en cron, GitHub Actions o
Vercel Cron sin instalar dependencias.
"""

PLACSP_ATOM_URL = (
    "https://contrataciondelestado.es/sindicacion/sindicacion_1143/"
    "licitacionesPerfilesContratanteCompleto3.atom"
)


@dataclass
class Licitacion:
    titulo: str
    enlace: str
    resumen: str
    actualizado: str
    importe: Optional[float] = None
    cpv_detectados: Optional[list[str]] = None


def filter_by_cpv_prefix(
    licitaciones: list[Licitacion], prefijo: str
) -> list[Licitacion]:
    """CPV-2008: "45" → construcción, "4521" → calderería, etc."""
    return [
        lic for lic in licitaciones
        if lic.cpv_detectados
        and any(cpv.startswith(prefijo) for cpv in lic.cpv_detectados)
    ]

Uso CLI

$ python placsp_fetcher.py --cpv 4521 --min 50000

generate-plantillas.mjs

Node.js ESM

arts. 140 + 210 LCSP · art. 85 RGLCAP

Generador del paquete de plantillas que ya se sirven en /recursos: declaración responsable LCSP (art. 140), acta de recepción (art. 210) y calculadora de baja temeraria en Excel con fórmulas (art. 85 RGLCAP). Requiere docx y exceljs.

/**
 * generate-plantillas.mjs
 *
 * Genera tres plantillas LCSP para descarga directa desde /recursos.
 * Stack: Node.js ESM + docx + exceljs.
 *
 * Salida:
 *   · declaracion-responsable-lcsp.docx  (art. 140 LCSP)
 *   · acta-recepcion-obra.docx           (art. 210 LCSP)
 *   · calculadora-baja-temeraria.xlsx    (art. 85 RGLCAP, fórmulas Excel)
 */

import { Document, Paragraph, HeadingLevel, AlignmentType, Packer } from 'docx';
import ExcelJS from 'exceljs';
import { writeFileSync } from 'node:fs';

async function generarDeclaracionResponsable() {
  // Cabecera institucional, declaraciones art. 140 LCSP, firma, etc.
}

async function generarActaRecepcion() {
  // Identificación del contrato, partes, acto con/sin reservas, plazo garantía.
}

async function generarCalculadoraBajaTemeraria() {
  // Pestaña Instrucciones + pestaña Calculadora con fórmulas vivas.
}

Uso CLI

$ npm install docx exceljs && node generate-plantillas.mjs

Datos abiertos · cuatro clientes

Consulta directa de fuentes oficiales.

BOE, DOGV, TED y BDNS desde su API pública, sin claves ni intermediarios y con la referencia oficial en cada resultado. Python con la biblioteca estándar, una consulta cada vez y salida en texto o en JSON.

boe_legislacion.py

Python 3.10+

BOE · API de datos abiertos de legislación consolidada

Busca normas por palabras del título o por número oficial, muestra sus metadatos y el texto vigente de un artículo concreto. La API devuelve todas las versiones de cada bloque: el script elige la vigente y dice qué norma le dio la redacción y desde cuándo. Recuerda al final que el texto consolidado no tiene valor jurídico oficial.

#!/usr/bin/env python3
"""
boe_legislacion.py
==================

Cliente mínimo de la API de datos abiertos del Boletín Oficial del Estado para
la legislación consolidada. Desde la línea de órdenes permite:

  * buscar normas por palabras de su título o por su número oficial (39/2015);
  * ver los metadatos de una norma (rango, fechas, situación, enlaces);
  * obtener el texto vigente de un artículo concreto o de cualquier otro bloque
    (preámbulo, disposiciones adicionales, transitorias, finales...).

Fuente oficial
--------------
Agencia Estatal Boletín Oficial del Estado, «Datos abiertos: API de
...

Uso CLI

$ python boe_legislacion.py articulo BOE-A-2015-10565 21

dogv_anuncios.py

Python 3.10+

DOGV · sumarios diarios del Diari Oficial de la Generalitat Valenciana

Lista las disposiciones de un día o de un intervalo, filtradas por sección o subsección (28, oposiciones y concursos; 62, contratos), e incluye los sumarios «bis», que sin pedirlos se pierden. Usa la API del propio portal, que no tiene documentación oficial y puede cambiar sin aviso.

#!/usr/bin/env python3
"""
dogv_anuncios.py
================

Cliente mínimo del Diari Oficial de la Generalitat Valenciana (DOGV). Lista,
en castellano, las disposiciones y anuncios publicados un día o en un
intervalo de días dentro de una subsección (o sección) del sumario.

Subsecciones más consultadas:
  28  II.A  Ofertas de empleo público, oposiciones y concursos
  62  V.B   Licitación y adjudicación de contratos
  44  III.B Subvenciones y becas
La orden «--subsecciones» muestra la lista completa con sus números.

...

Uso CLI

$ python dogv_anuncios.py --fecha 2026-10-30 --subseccion 28

ted_buscar.py

Python 3.10+

TED · API v3 de búsqueda (Diario Oficial de la UE)

Busca anuncios de contratación europeos por país del comprador, código CPV y fechas, con número de publicación, comprador, fecha límite de ofertas y enlace. Sin clave y con una sola consulta por ejecución.

#!/usr/bin/env python3
"""
ted_buscar.py
=============

Cliente mínimo de la API de búsqueda de TED (Tenders Electronic Daily), el
suplemento del Diario Oficial de la Unión Europea dedicado a la contratación
pública. Busca anuncios por país del comprador, código CPV y fechas de
publicación, y muestra de cada uno el número de publicación, el título, el
comprador, la fecha límite de presentación de ofertas y el enlace al anuncio.

Fuente oficial
--------------
Oficina de Publicaciones de la Unión Europea, API de TED, versión 3
(búsqueda de anuncios, sin autenticación).
...

Uso CLI

$ python ted_buscar.py --pais ESP --cpv 72 --desde 2026-10-01 --hasta 2026-10-31

bdns_convocatorias.py

Python 3.10+

BDNS · Sistema Nacional de Publicidad de Subvenciones (IGAE)

Busca convocatorias por palabras del título y fecha de registro, y muestra el detalle de una convocatoria: presupuesto, plazo y diario oficial del extracto. Deduce el estado del plazo a partir de las fechas, porque el indicador «abierto» de la BDNS no es fiable.

#!/usr/bin/env python3
"""
bdns_convocatorias.py
=====================

Cliente mínimo de la API REST de la Base de Datos Nacional de Subvenciones
(BDNS), la que se consulta en el Sistema Nacional de Publicidad de
Subvenciones y Ayudas Públicas (infosubvenciones.es). Permite:

  * buscar convocatorias por palabras del título y por fecha de registro,
    mostrando número BDNS, título, órgano convocante, fecha y enlace;
  * ver el detalle de una convocatoria por su número BDNS: presupuesto,
    beneficiarios, plazo de solicitud, bases reguladoras y diario oficial en
    que se publicó el extracto.

...

Uso CLI

$ python bdns_convocatorias.py buscar "eficiencia energética" --desde 2026-10-01

Documentación del paquete

README con tabla de contenidos, ejemplos de uso por archivo, normativa de referencia, licencia y vías de contribución.

Descargar README.md

Repositorio público

Próximamente como repositorio GitHub independiente con histórico de cambios, issues, contribuciones vía pull request y releases firmadas.

Mientras tanto, cada archivo de esta página es la versión estable y autocontenida. Cita lloretia.com/codigo como fuente.

Normativa de referencia

Normas implementadas.

Ley 9/2017 LCSP

Ley de Contratos del Sector Público. Marco general para declaración responsable (art. 140), acta de recepción (art. 210) y baja anormal (art. 149).

RD 1098/2001 (RGLCAP)

Reglamento General LCAP. El art. 85 fija las cuatro reglas de baja temeraria que implementan los archivos de esta página.

Reg. (UE) 2024/1689 (EU AI Act)

Reglamento europeo de IA. El art. 50 (efectividad 2 ago 2026) obliga a marcar técnicamente el output sintético y a informar al usuario en interacciones con IA.

RGPD + LOPDGDD

Marco español de protección de datos. Compatible con todos los scripts: ninguno persiste datos personales y el fetcher PLACSP trabaja sobre publicación oficial.