Primera version funcional
This commit is contained in:
parent
6ec347f3f4
commit
240be1157b
15
README.md
15
README.md
|
|
@ -36,3 +36,18 @@ python main.py
|
||||||
```
|
```
|
||||||
|
|
||||||
### Uso del script
|
### Uso del script
|
||||||
|
```bash
|
||||||
|
python main.py {ap,vacaciones} fecha --dias
|
||||||
|
{ap,vacaciones} Tipo de solicitud
|
||||||
|
fecha Fecha, rango o lista
|
||||||
|
--dias nDias en caso de vacaciones el nº de dias habiles (opcional, en caso de no especificarlo se le solicita por prompt)
|
||||||
|
|
||||||
|
Ejemplos:
|
||||||
|
python main.py ap 17/02/26
|
||||||
|
python main.py ap 17/02/26-19/02/26
|
||||||
|
python main.py ap 17/02/26,20/02/26,25/02/26
|
||||||
|
|
||||||
|
python main.py vacaciones 16/02/26-22/02/26 'Se solicitaran los dias habiles mediante el prompt'
|
||||||
|
python main.py vacaciones 16/02/26-22/02/26 --dias 5
|
||||||
|
|
||||||
|
```/
|
||||||
63
docs/campos
63
docs/campos
|
|
@ -1,63 +0,0 @@
|
||||||
DNI
|
|
||||||
Nombre
|
|
||||||
Apellido 1
|
|
||||||
Apellido 2
|
|
||||||
Cuerpo o escala
|
|
||||||
Área
|
|
||||||
Primergrado
|
|
||||||
segundoGrado
|
|
||||||
ausencia1hJornada
|
|
||||||
ausencia1hFraccionada
|
|
||||||
reduccion1h
|
|
||||||
reducciónMediaHora
|
|
||||||
horasSindicales
|
|
||||||
diasSindicales
|
|
||||||
diasHabiles
|
|
||||||
PermisoParto
|
|
||||||
permisoadopcion
|
|
||||||
PermisoPaternidad
|
|
||||||
fallecimiento
|
|
||||||
trasladoSin
|
|
||||||
trasladoCon
|
|
||||||
examenesFinales
|
|
||||||
examenesPrenatales
|
|
||||||
Lactancia
|
|
||||||
NacimientoPrematuro
|
|
||||||
indispensable
|
|
||||||
moscoso
|
|
||||||
matrimonio
|
|
||||||
sindicales
|
|
||||||
CursoOrganismo
|
|
||||||
CursoAGE
|
|
||||||
CursoSindicatos
|
|
||||||
CursoPracticas
|
|
||||||
TomaProvision
|
|
||||||
TomaNuevoCuerpo
|
|
||||||
jubilacion
|
|
||||||
InteresParticular
|
|
||||||
FamiliarGrave
|
|
||||||
LicenciaEstudio
|
|
||||||
LicenciaPropios
|
|
||||||
LicenciaDesarrollo
|
|
||||||
TotalEnfermedadSin
|
|
||||||
TotalEnfermedadCon
|
|
||||||
ParcialEnfermedad
|
|
||||||
GestiónOficial
|
|
||||||
GestiónPersonal
|
|
||||||
ConisionServicio
|
|
||||||
viajeOficial
|
|
||||||
PorNocturnas
|
|
||||||
FueraHorario
|
|
||||||
refuerzos
|
|
||||||
noBeneficios
|
|
||||||
curso
|
|
||||||
decision
|
|
||||||
NumDiasHabiles
|
|
||||||
nmHorasSidicales
|
|
||||||
Otros
|
|
||||||
PERÍODO DE TIEMPO POR EL QUE SE SOLICITA
|
|
||||||
Imprimir
|
|
||||||
OposicionesInterna
|
|
||||||
numDiasSindicales
|
|
||||||
Fecha
|
|
||||||
guarda
|
|
||||||
13
docs/config.json
Normal file
13
docs/config.json
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"datos_personales": {
|
||||||
|
"DNI": "33340763D",
|
||||||
|
"Nombre": "MARCOS",
|
||||||
|
"Apellido 1": "LOPEZ",
|
||||||
|
"Apellido 2": "GOMEZ",
|
||||||
|
"Cuerpo o escala": "C.TEC. AUX. DE INFORMATICA ADMON. ESTADO"
|
||||||
|
},
|
||||||
|
"rutas": {
|
||||||
|
"plantilla": "./docs/Plantilla.pdf",
|
||||||
|
"certificado": "./certificado/certificado.p12"
|
||||||
|
}
|
||||||
|
}
|
||||||
37
main.py
37
main.py
|
|
@ -1,30 +1,38 @@
|
||||||
import argparse
|
import argparse
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
|
import json
|
||||||
import warnings
|
import warnings
|
||||||
warnings.filterwarnings("ignore", category=UserWarning, module="pyhanko")
|
|
||||||
import getpass
|
import getpass
|
||||||
from pypdf import PdfReader, PdfWriter
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from pypdf import PdfReader, PdfWriter
|
||||||
from pyhanko.pdf_utils.incremental_writer import IncrementalPdfFileWriter
|
from pyhanko.pdf_utils.incremental_writer import IncrementalPdfFileWriter
|
||||||
from pyhanko.sign import signers, fields
|
from pyhanko.sign import signers, fields
|
||||||
from pyhanko.stamp import TextStampStyle
|
from pyhanko.stamp import TextStampStyle
|
||||||
from pyhanko.pdf_utils.layout import SimpleBoxLayoutRule, AxisAlignment
|
from pyhanko.pdf_utils.layout import SimpleBoxLayoutRule, AxisAlignment
|
||||||
from pyhanko.pdf_utils.text import TextBoxStyle
|
from pyhanko.pdf_utils.text import TextBoxStyle
|
||||||
|
|
||||||
|
# Ignorar avisos de pyhanko
|
||||||
|
warnings.filterwarnings("ignore", category=UserWarning, module="pyhanko")
|
||||||
|
|
||||||
class SolicitudRRHH:
|
class SolicitudRRHH:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.cert_path = os.path.join(os.path.dirname(__file__), "certificado", "certificado.p12")
|
self.base_path = os.path.dirname(os.path.abspath(__file__))
|
||||||
self.datos_personales = {
|
self.config = self._cargar_configuracion()
|
||||||
"DNI": "33340763D",
|
|
||||||
"Nombre": "MARCOS",
|
self.cert_path = os.path.join(self.base_path, self.config["rutas"]["certificado"])
|
||||||
"Apellido 1": "LOPEZ",
|
self.datos_personales = self.config["datos_personales"]
|
||||||
"Apellido 2": "GOMEZ",
|
|
||||||
"Cuerpo o escala": "C.TEC. AUX. DE INFORMATICA ADMON. ESTADO"
|
|
||||||
}
|
|
||||||
self.args = self._parsear_argumentos()
|
self.args = self._parsear_argumentos()
|
||||||
self.num_dias = self._obtener_num_dias()
|
self.num_dias = self._obtener_num_dias()
|
||||||
|
|
||||||
|
def _cargar_configuracion(self):
|
||||||
|
config_path = os.path.join(self.base_path, "docs/config.json")
|
||||||
|
if not os.path.exists(config_path):
|
||||||
|
raise FileNotFoundError(f"No se encuentra el archivo de configuración: {config_path}")
|
||||||
|
with open(config_path, 'r', encoding='utf-8') as f:
|
||||||
|
return json.load(f)
|
||||||
|
|
||||||
def _validar_fecha(self, fecha_str):
|
def _validar_fecha(self, fecha_str):
|
||||||
patron_fecha = r"\d{2}/\d{2}/\d{2}"
|
patron_fecha = r"\d{2}/\d{2}/\d{2}"
|
||||||
patron_completo = rf"^{patron_fecha}((-{patron_fecha})|(,{patron_fecha})*)?$"
|
patron_completo = rf"^{patron_fecha}((-{patron_fecha})|(,{patron_fecha})*)?$"
|
||||||
|
|
@ -53,7 +61,7 @@ class SolicitudRRHH:
|
||||||
|
|
||||||
def _firmar_pdf(self, archivo_entrada, archivo_salida):
|
def _firmar_pdf(self, archivo_entrada, archivo_salida):
|
||||||
if not os.path.exists(self.cert_path):
|
if not os.path.exists(self.cert_path):
|
||||||
print(f"⚠️ No se encontró el certificado.")
|
print(f"⚠️ No se encontró el certificado en {self.cert_path}. Se guardará sin firmar.")
|
||||||
os.rename(archivo_entrada, archivo_salida)
|
os.rename(archivo_entrada, archivo_salida)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -61,7 +69,8 @@ class SolicitudRRHH:
|
||||||
w = IncrementalPdfFileWriter(inf)
|
w = IncrementalPdfFileWriter(inf)
|
||||||
signer = signers.SimpleSigner.load_pkcs12(
|
signer = signers.SimpleSigner.load_pkcs12(
|
||||||
pfx_file=self.cert_path,
|
pfx_file=self.cert_path,
|
||||||
passphrase=self._obtener_passw_cert())
|
passphrase=self._obtener_passw_cert()
|
||||||
|
)
|
||||||
|
|
||||||
estilo = TextStampStyle(
|
estilo = TextStampStyle(
|
||||||
border_width=0,
|
border_width=0,
|
||||||
|
|
@ -84,7 +93,8 @@ class SolicitudRRHH:
|
||||||
with open(archivo_salida, 'wb') as outf:
|
with open(archivo_salida, 'wb') as outf:
|
||||||
pdf_signer.sign_pdf(w, output=outf)
|
pdf_signer.sign_pdf(w, output=outf)
|
||||||
|
|
||||||
def generar_pdf(self, path_plantilla="./docs/Plantilla.pdf"):
|
def generar_pdf(self):
|
||||||
|
path_plantilla = os.path.join(self.base_path, self.config["rutas"]["plantilla"])
|
||||||
reader = PdfReader(path_plantilla)
|
reader = PdfReader(path_plantilla)
|
||||||
writer = PdfWriter()
|
writer = PdfWriter()
|
||||||
writer.clone_reader_document_root(reader)
|
writer.clone_reader_document_root(reader)
|
||||||
|
|
@ -114,7 +124,6 @@ class SolicitudRRHH:
|
||||||
|
|
||||||
writer.set_need_appearances_writer()
|
writer.set_need_appearances_writer()
|
||||||
|
|
||||||
# --- FLUJO DE GUARDADO Y FIRMA ---
|
|
||||||
nombre_final = self._generar_nombre_archivo()
|
nombre_final = self._generar_nombre_archivo()
|
||||||
temp_file = "temp_solicitud.pdf"
|
temp_file = "temp_solicitud.pdf"
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user