138 lines
5.4 KiB
Python
138 lines
5.4 KiB
Python
import argparse
|
|
import re
|
|
import os
|
|
import warnings
|
|
warnings.filterwarnings("ignore", category=UserWarning, module="pyhanko")
|
|
import getpass
|
|
from pypdf import PdfReader, PdfWriter
|
|
from datetime import datetime
|
|
from pyhanko.pdf_utils.incremental_writer import IncrementalPdfFileWriter
|
|
from pyhanko.sign import signers, fields
|
|
from pyhanko.stamp import TextStampStyle
|
|
from pyhanko.pdf_utils.layout import SimpleBoxLayoutRule, AxisAlignment
|
|
from pyhanko.pdf_utils.text import TextBoxStyle
|
|
|
|
class SolicitudRRHH:
|
|
def __init__(self):
|
|
self.cert_path = os.path.join(os.path.dirname(__file__), "certificado", "certificado.p12")
|
|
self.datos_personales = {
|
|
"DNI": "33340763D",
|
|
"Nombre": "MARCOS",
|
|
"Apellido 1": "LOPEZ",
|
|
"Apellido 2": "GOMEZ",
|
|
"Cuerpo o escala": "C.TEC. AUX. DE INFORMATICA ADMON. ESTADO"
|
|
}
|
|
self.args = self._parsear_argumentos()
|
|
self.num_dias = self._obtener_num_dias()
|
|
|
|
def _validar_fecha(self, fecha_str):
|
|
patron_fecha = r"\d{2}/\d{2}/\d{2}"
|
|
patron_completo = rf"^{patron_fecha}((-{patron_fecha})|(,{patron_fecha})*)?$"
|
|
if re.match(patron_completo, fecha_str):
|
|
return fecha_str
|
|
raise argparse.ArgumentTypeError(f"Formato de fecha inválido: {fecha_str}")
|
|
|
|
def _parsear_argumentos(self):
|
|
parser = argparse.ArgumentParser(description="Automatización de solicitudes RRHH")
|
|
parser.add_argument("tipo", choices=["ap", "vacaciones"], help="Tipo de solicitud")
|
|
parser.add_argument("fecha", type=self._validar_fecha, help="Fecha, rango o lista")
|
|
parser.add_argument("--dias", type=int, help="Número de días hábiles")
|
|
return parser.parse_args()
|
|
|
|
def _obtener_num_dias(self):
|
|
if self.args.tipo == "vacaciones":
|
|
if self.args.dias: return self.args.dias
|
|
while True:
|
|
try:
|
|
return int(input("👉 Introduce el Nº de días hábiles de vacaciones: "))
|
|
except ValueError: print("❌ Introduce un número entero válido.")
|
|
return None
|
|
|
|
def _obtener_passw_cert(self):
|
|
return str(getpass.getpass(prompt="👉 Introduce la contraseña del certificado: ")).encode("utf-8")
|
|
|
|
def _firmar_pdf(self, archivo_entrada, archivo_salida):
|
|
if not os.path.exists(self.cert_path):
|
|
print(f"⚠️ No se encontró el certificado.")
|
|
os.rename(archivo_entrada, archivo_salida)
|
|
return
|
|
|
|
with open(archivo_entrada, 'rb') as inf:
|
|
w = IncrementalPdfFileWriter(inf)
|
|
signer = signers.SimpleSigner.load_pkcs12(
|
|
pfx_file=self.cert_path,
|
|
passphrase=self._obtener_passw_cert())
|
|
|
|
estilo = TextStampStyle(
|
|
border_width = 0,
|
|
text_box_style = TextBoxStyle(font_size = 10),
|
|
inner_content_layout=SimpleBoxLayoutRule(x_align=AxisAlignment.ALIGN_MIN,y_align=AxisAlignment.ALIGN_MAX) ,
|
|
stamp_text='Firmado por: \n%(signer)s\nFecha: %(ts)s'
|
|
)
|
|
|
|
pdf_signer = signers.PdfSigner(
|
|
signature_meta=signers.PdfSignatureMetadata(field_name='Firma_Visible'),
|
|
signer=signer,
|
|
stamp_style=estilo,
|
|
new_field_spec=fields.SigFieldSpec(
|
|
'Firma_Visible',
|
|
box=(350, 20, 550, 100),
|
|
on_page=1
|
|
)
|
|
)
|
|
|
|
with open(archivo_salida, 'wb') as outf:
|
|
pdf_signer.sign_pdf(w, output=outf)
|
|
|
|
def generar_pdf(self, path_plantilla="./docs/Plantilla.pdf"):
|
|
reader = PdfReader(path_plantilla)
|
|
writer = PdfWriter()
|
|
writer.clone_reader_document_root(reader)
|
|
|
|
fechas_raw = self.args.fecha
|
|
if "-" in fechas_raw:
|
|
f = fechas_raw.split("-")
|
|
texto_fechas = f"Del {f[0]} al {f[1]}"
|
|
elif "," in fechas_raw:
|
|
texto_fechas = f"{fechas_raw.replace(',', ', ')}"
|
|
else:
|
|
texto_fechas = fechas_raw
|
|
|
|
campos_finales = {**self.datos_personales}
|
|
|
|
if self.args.tipo == "ap":
|
|
campos_finales["moscoso"] = "/Yes"
|
|
else:
|
|
campos_finales["diasHabiles"] = "/Yes"
|
|
campos_finales["NumDiasHabiles"] = str(self.num_dias)
|
|
|
|
campos_finales["PERÍODO DE TIEMPO POR EL QUE SE SOLICITA"] = texto_fechas
|
|
campos_finales["Fecha"] = datetime.now().strftime("%d/%m/%Y")
|
|
|
|
for page in writer.pages:
|
|
writer.update_page_form_field_values(page, campos_finales)
|
|
|
|
writer.set_need_appearances_writer()
|
|
|
|
# --- FLUJO DE GUARDADO Y FIRMA ---
|
|
nombre_final = self._generar_nombre_archivo()
|
|
temp_file = "temp_solicitud.pdf"
|
|
|
|
with open(temp_file, "wb") as f:
|
|
writer.write(f)
|
|
|
|
self._firmar_pdf(temp_file, nombre_final)
|
|
|
|
if os.path.exists(temp_file):
|
|
os.remove(temp_file)
|
|
|
|
print(f"✅ Proceso completado con éxito: {nombre_final}")
|
|
|
|
def _generar_nombre_archivo(self):
|
|
tipo_limpio = self.args.tipo.upper()
|
|
primera_fecha = re.split(r'[,-]', self.args.fecha)[0].replace("/", "-")
|
|
return f"{self.datos_personales['Apellido 1']}_{self.datos_personales['Apellido 2']}_{self.datos_personales['Nombre']}_{tipo_limpio}_{primera_fecha}.pdf"
|
|
|
|
if __name__ == "__main__":
|
|
solicitud = SolicitudRRHH()
|
|
solicitud.generar_pdf() |