futjesus/liquidaciones

★ 0Forks 0TypeScriptGitHub ↗Compare

Project website ↗

README

Separador de liquidaciones

App web que hace lo mismo que split_liquidaciones.py: se sube el PDF mensual de liquidaciones, se separa en un PDF por página nombrado <Sr(a)> - <Mes>.pdf, y se descarga todo en un ZIP. Detrás de un login simple con usuario y contraseña.

Cómo funciona

Paso Script de Python Esta app
Leer texto de cada página PyPDF2.PdfReader pdfjs-dist (src/lib/pdf-text.ts)
Detectar nombre y mes Sr(a): / Mes: con regex los mismos regex (src/lib/split.ts)
Escribir un PDF por página PdfWriter pdf-lib
Empaquetar zipfile jszip

El nombre del ZIP se deduce del mes detectado en el PDF (Junio 2026 → liquidaciones_junio_2026.zip), igual que la convención del script original.

Los nombres generados se verificaron contra las 544 páginas de los 8 PDF de ejemplo y coinciden exactamente con los que produjo el script de Python. Puedes repetir la comprobación en cualquier momento:

npm run verify

pdfjs en el bundle serverless

pdfjs llega a su worker mediante un import() calculado, así que el rastreador de archivos de Next no lo ve y deja pdf.worker.mjs fuera de la función. En Vercel eso rompe /api/split con:

Setting up fake worker failed: Cannot find module '/var/task/node_modules/pdfjs-dist/legacy/build/pdf.worker.mjs'

El arreglo es el outputFileTracingIncludes de next.config.ts, que fuerza la inclusión del worker. No borres esa entrada. Para reproducir el problema en local sin desplegar, añade output: "standalone" al config, compila y arranca node .next/standalone/server.js: el standalone contiene exactamente los archivos que rastrea Next, o sea los mismos que empaqueta Vercel.

El aviso Cannot load "@napi-rs/canvas" era inocuo — pdfjs solo usa canvas para renderizar y aquí únicamente extraemos texto — pero se silencia con verbosity: VerbosityLevel.ERRORS en src/lib/pdf-text.ts.

Dos diferencias intencionadas

  • Páginas duplicadas. Si dos páginas dan el mismo nombre y mes, el script de Python sobreescribe el archivo y mete una entrada duplicada en el ZIP; aquí la segunda pasa a ser Nombre - Mes (2).pdf para no perder ninguna página.
  • Páginas sin datos. Se mantiene el comportamiento original (Empleado_NN, Mes_desconocido) pero la interfaz avisa de cuántas páginas quedaron así.

Desarrollo

npm install
cp .env.example .env.local   # opcional
npm run dev                  # http://localhost:3000

Credenciales por defecto: admin / liquidaciones2026.

Despliegue en Vercel

npx vercel        # preview
npx vercel --prod

Marca este directorio (app/) como Root Directory del proyecto. No hace falta configuración extra: Vercel detecta Next.js.

Después define las variables de entorno en Settings → Environment Variables:

Variable Para qué
AUTH_USERNAME usuario del login
AUTH_PASSWORD contraseña del login
AUTH_SECRET clave de firma de la cookie (openssl rand -hex 32)

Sin ellas la app arranca con los valores por defecto del código, así que cámbialas antes de exponerla.

Límites a tener en cuenta

  • Subida: Vercel corta los cuerpos de petición sobre ~4,5 MB. Los PDF de ejemplo pesan ~400 KB, con mucho margen.
  • Descarga: el ZIP también viaja por la función serverless, con el mismo tope de ~4,5 MB. El mayor de los ejemplos (80 páginas) genera ~3,7 MB — entra, pero un PDF bastante más grande no cabría. Si llegas a ese punto, la salida natural es mover el procesado al navegador (las tres librerías funcionan en cliente).
  • Tiempo: el límite de la función está en 60 s (src/app/api/split/route.ts); separar 65 páginas tarda unos 0,3 s.

Autenticación

Un solo usuario hardcodeado y una cookie HttpOnly firmada con HMAC-SHA256 que caduca a las 12 h (src/lib/auth.ts). Todo lo que no sea /login y /api/login pasa por src/proxy.ts. Es suficiente para restringir el acceso a un equipo pequeño, pero no es un sistema multiusuario: la contraseña es compartida y no hay registro de accesos.

Contributors

futjesus

Issues