se agrega archivos para la instalación en Docker

This commit is contained in:
George committed 2026-08-04 17:57:43 -05:00
1 parent 533105e7c3
commit cf2c1ee147
28 files changed
+1430 -501

No files matched your search

+102 -158
View File
@@ -1,188 +1,132 @@
import os
import shutil
########################################################
def calcular_puntuacion(nombre_archivo, ruc, tipo, serie_numero):
"""
Calcula una puntuación de 0 a 4 según cuántos elementos coinciden en el nombre del archivo.
serie_numero se descompone en serie y número.
"""
puntos = 0
nombre_archivo = nombre_archivo.upper()
# 1. RUC
if ruc and ruc != "N/A" and ruc in nombre_archivo:
puntos += 1
# 2. Tipo
if tipo and tipo != "99" and tipo in nombre_archivo:
puntos += 1
# 3. Serie y 4. Número
if "-" in serie_numero:
partes = serie_numero.split("-")
serie = partes[0].upper()
numero = partes[1]
if serie in nombre_archivo:
puntos += 1
if numero in nombre_archivo:
puntos += 1
return puntos
# ========================================================================
def tiene_datos_parciales(m):
"""True si el archivo tiene al menos un campo útil, aunque incompleto."""
if m['ruc'] not in ("N/A", "Desconocido"):
return True
if m['serie_numero'] not in ("No encontrado", "N/A"):
return True
if m['tipo'] != "99":
return True
return False
########################################################
def procesar_renombrado_agrupado(email_obj, ruta_base):
# ========================================================================
def renombrar_archivos_por_metadata(metadatos, ruta_base):
"""
Lógica de agrupación y renombrado de archivos según puntuación y tipo.
Renombra cada archivo según su propia metadata extraída.
- XML/PDF con archivo_propuesto válido: se renombra a {archivo_propuesto}{extension}
- CDR (tipo 'CDR'): se renombra igual (archivo_propuesto ya incluye CDR)
- Sin metadata válida (archivo_propuesto is None): se deja intacto (será eliminado al limpiar)
Retorna la lista de metadatos actualizada con los nombres finales.
"""
metadatos = email_obj.get('metadatos_adjuntos', [])
tipos_permitidos = ["01", "03", "07", "08", "02", "09", "14"]
# 1. Identificar "Pivotes" (pivotes para agrupar)
# Preferencia: XML Maestros. Fallback: PDFs con metadata válida si no hay XMLs.
xml_maestros = [m for m in metadatos if m['extension'] == ".xml" and m['tipo'] in tipos_permitidos]
if xml_maestros:
pivotes = xml_maestros
else:
# En correos solo PDF, tratamos a cada PDF con nombre propuesto como un pivote
pivotes = [m for m in metadatos if m['extension'] == ".pdf" and m['archivo_propuesto'] is not None]
if not pivotes:
return {} # Nada que agrupar
nuevos_archivos = []
mapeo_renombrado = {} # original -> nuevo
agrupacion = {} # archivo_propuesto -> [lista de nombres nuevos]
# Inicializar el diccionario de agrupación con los nombres de los pivotes
for p in pivotes:
agrupacion[p['archivo_propuesto']] = []
# 2. Agrupar cada archivo con su mejor pivote
for m in metadatos:
nombre_original = m['archivo']
extension = m['extension'].lower()
# Si es un pivote, su nombre es directo y ya está inicializado
if m in pivotes:
nombre_nuevo = f"{m['archivo_propuesto']}{extension}"
mapeo_renombrado[nombre_original] = nombre_nuevo
agrupacion[m['archivo_propuesto']].append(nombre_nuevo)
else:
# Buscar el mejor match entre los pivotes que aún acepten este tipo de archivo
mejor_pivote = None
max_puntos = -1
is_cdr = m['tipo'] == "CDR" or "R-" in nombre_original or "R_" in nombre_original or "CDR" in nombre_original.upper()
is_pdf = extension == ".pdf"
is_xml = extension == ".xml" and not is_cdr
for p in pivotes:
p_prop = p['archivo_propuesto']
grupo_actual = agrupacion[p_prop]
ya_tiene_pdf = any(f.lower().endswith('.pdf') for f in grupo_actual)
ya_tiene_cdr = any(f.startswith('CDR-') for f in grupo_actual)
if (is_pdf and ya_tiene_pdf) or (is_cdr and ya_tiene_cdr) or is_xml:
continue
puntos = calcular_puntuacion(
nombre_original,
p['ruc'],
p['tipo'],
p['serie_numero']
)
if puntos > max_puntos:
max_puntos = puntos
mejor_pivote = p
if mejor_pivote and max_puntos > 0:
prefix = "CDR-" if is_cdr else ""
nombre_nuevo = f"{prefix}{mejor_pivote['archivo_propuesto']}{extension}"
mapeo_renombrado[nombre_original] = nombre_nuevo
agrupacion[mejor_pivote['archivo_propuesto']].append(nombre_nuevo)
else:
# Si no hay match, va a OTROS
mapeo_renombrado[nombre_original] = nombre_original
if "OTROS" not in agrupacion: agrupacion["OTROS"] = []
agrupacion["OTROS"].append(nombre_original)
extension = m['extension']
propuesto = m.get('archivo_propuesto')
# 3. Ejecutar el renombrado físico y actualizar metadatos
for m in metadatos:
nombre_original = m['archivo']
nombre_nuevo = mapeo_renombrado.get(nombre_original)
if nombre_nuevo and nombre_nuevo != nombre_original:
ruta_old = os.path.join(ruta_base, nombre_original)
ruta_new = os.path.join(ruta_base, nombre_nuevo)
try:
if os.path.exists(ruta_old):
# Si el destino ya existe, borramos para sobreescribir (o podrías manejarlo de otra forma)
if os.path.exists(ruta_new) and ruta_old != ruta_new:
os.remove(ruta_new)
os.rename(ruta_old, ruta_new)
m['archivo'] = nombre_nuevo
except Exception as e:
print(f" ⚠️ Error renombrando {nombre_original}: {e}")
if propuesto is None:
continue
# 4. Actualizar la lista de archivos en el email_obj
email_obj['archivos'] = [m['archivo'] for m in metadatos]
return agrupacion
nuevo_nombre = f"{propuesto}{extension}"
if nuevo_nombre == nombre_original:
continue
########################################################
def mover_archivos_a_resultado(email_obj, ruta_origen, ruta_destino):
ruta_old = os.path.join(ruta_base, nombre_original)
ruta_new = os.path.join(ruta_base, nuevo_nombre)
try:
if os.path.exists(ruta_old):
if os.path.exists(ruta_new) and ruta_old != ruta_new:
os.remove(ruta_new)
os.rename(ruta_old, ruta_new)
m['archivo'] = nuevo_nombre
except Exception as e:
print(f" ⚠️ Error renombrando '{nombre_original}': {e}")
return metadatos
# ========================================================================
def mover_validos_a_resultado(metadatos, ruta_origen, ruta_destino):
"""
Mueve los archivos procesados de la carpeta temporal a la carpeta final de resultados.
Solo mueve archivos que pertenecen a un grupo válido (basado en archivo_propuesto).
Excluye los archivos en la categoría 'OTROS'.
Mueve solo los archivos que tienen metadata válida (archivo_propuesto no None)
desde la carpeta de descarga a la carpeta de resultados.
"""
agrupacion = email_obj.get('agrupacion_archivos', {})
if not agrupacion:
return
if not os.path.exists(ruta_destino):
os.makedirs(ruta_destino)
print(f" 📁 Carpeta de destino creada: {ruta_destino}")
for key, archivos in agrupacion.items():
if key == "OTROS":
continue # No mover archivos no identificados
for archivo in archivos:
ruta_old = os.path.join(ruta_origen, archivo)
ruta_new = os.path.join(ruta_destino, archivo)
try:
if os.path.exists(ruta_old):
if os.path.exists(ruta_new) and ruta_old != ruta_new:
os.remove(ruta_new)
os.rename(ruta_old, ruta_new)
except Exception as e:
print(f" ⚠️ Error trasladando {archivo} a resultado: {e}")
movidos = 0
for m in metadatos:
if m.get('archivo_propuesto') is None:
continue
########################################################
archivo = m['archivo']
ruta_old = os.path.join(ruta_origen, archivo)
ruta_new = os.path.join(ruta_destino, archivo)
try:
if os.path.exists(ruta_old):
if os.path.exists(ruta_new) and ruta_old != ruta_new:
os.remove(ruta_new)
os.rename(ruta_old, ruta_new)
movidos += 1
except Exception as e:
print(f" ⚠️ Error trasladando '{archivo}' a resultado: {e}")
if movidos:
print(f" 📦 {movidos} archivo(s) movido(s) a resultado.")
# ========================================================================
def mover_a_evaluar(metadatos, ruta_origen, ruta_evaluar):
"""
Mueve archivos con metadata parcial a la carpeta evaluar/ para revisión.
Conserva el nombre original del archivo (sin renombrar).
"""
if not metadatos:
return
if not os.path.exists(ruta_evaluar):
os.makedirs(ruta_evaluar)
movidos = 0
for m in metadatos:
archivo = m['archivo']
ruta_old = os.path.join(ruta_origen, archivo)
ruta_new = os.path.join(ruta_evaluar, archivo)
try:
if os.path.exists(ruta_old):
if os.path.exists(ruta_new) and ruta_old != ruta_new:
os.remove(ruta_new)
os.rename(ruta_old, ruta_new)
movidos += 1
except Exception as e:
print(f" ⚠️ Error moviendo '{archivo}' a evaluar: {e}")
if movidos:
print(f" 🔍 {movidos} archivo(s) movido(s) a evaluar (metadata parcial).")
# ========================================================================
def limpiar_carpeta_descarga(ruta):
"""
Elimina todos los archivos dentro de la carpeta de descarga para dejarla limpia.
Elimina todos los archivos y subcarpetas dentro de la carpeta de descarga.
Omite la subcarpeta 'evaluar/' para no borrar archivos pendientes de revisión.
"""
if not os.path.exists(ruta):
return
print(f" 🧹 Limpiando carpeta de descarga: {ruta}")
print(f" 🧹 Limpiando carpeta de descarga")
for archivo in os.listdir(ruta):
if archivo == "evaluar":
continue
ruta_archivo = os.path.join(ruta, archivo)
try:
if os.path.isfile(ruta_archivo):
os.remove(ruta_archivo)
elif os.path.isdir(ruta_archivo):
import shutil
shutil.rmtree(ruta_archivo)
except Exception as e:
print(f" ⚠️ No se pudo eliminar {archivo}: {e}")
print(f" ⚠️ No se pudo eliminar '{archivo}': {e}")
########################################################
# ========================================================================