Backend v1.0.82: PDF con logos dual (empresa + checklist)
- Generación de PDF ahora muestra dos logos en el encabezado - Logo izquierda: logo de la empresa (AIConfiguration) - Logo derecha: logo del checklist específico (o empresa como fallback) - Nueva función helper load_logo() para reutilización - Layout horizontal con tabla de 3 columnas para separación visual - Frontend: sin cambios (v1.0.79)
This commit is contained in:
@@ -204,7 +204,7 @@ def send_completed_inspection_to_n8n(inspection, db):
|
|||||||
# No lanzamos excepción para no interrumpir el flujo normal
|
# No lanzamos excepción para no interrumpir el flujo normal
|
||||||
|
|
||||||
|
|
||||||
BACKEND_VERSION = "1.0.81"
|
BACKEND_VERSION = "1.0.82"
|
||||||
app = FastAPI(title="Checklist Inteligente API", version=BACKEND_VERSION)
|
app = FastAPI(title="Checklist Inteligente API", version=BACKEND_VERSION)
|
||||||
|
|
||||||
# S3/MinIO configuration
|
# S3/MinIO configuration
|
||||||
@@ -1401,57 +1401,97 @@ def generate_inspection_pdf(inspection_id: int, db: Session) -> str:
|
|||||||
mechanic = db.query(models.User).filter(models.User.id == inspection.mechanic_id).first()
|
mechanic = db.query(models.User).filter(models.User.id == inspection.mechanic_id).first()
|
||||||
checklist = db.query(models.Checklist).filter(models.Checklist.id == inspection.checklist_id).first()
|
checklist = db.query(models.Checklist).filter(models.Checklist.id == inspection.checklist_id).first()
|
||||||
|
|
||||||
# Obtener logo principal de configuración para el PDF
|
# Obtener logo principal de configuración (empresa)
|
||||||
config = db.query(models.AIConfiguration).filter(models.AIConfiguration.is_active == True).first()
|
config = db.query(models.AIConfiguration).filter(models.AIConfiguration.is_active == True).first()
|
||||||
logo_url_to_use = None
|
company_logo_url = None
|
||||||
if config and getattr(config, "logo_url", None):
|
if config and getattr(config, "logo_url", None):
|
||||||
logo_url_to_use = config.logo_url
|
company_logo_url = config.logo_url
|
||||||
print(f"📸 Usando logo principal de configuración: {logo_url_to_use}")
|
print(f"📸 Logo de la empresa: {company_logo_url}")
|
||||||
else:
|
else:
|
||||||
print("ℹ️ No hay logo principal configurado")
|
print("ℹ️ No hay logo de empresa configurado")
|
||||||
|
|
||||||
|
# Obtener logo del checklist
|
||||||
|
checklist_logo_url = None
|
||||||
|
if checklist and getattr(checklist, "logo_url", None):
|
||||||
|
checklist_logo_url = checklist.logo_url
|
||||||
|
print(f"📋 Logo del checklist: {checklist_logo_url}")
|
||||||
|
else:
|
||||||
|
# Si no tiene logo, usar el de la empresa como fallback
|
||||||
|
checklist_logo_url = company_logo_url
|
||||||
|
print(f"ℹ️ Checklist sin logo, usando logo de empresa como fallback")
|
||||||
|
|
||||||
# ===== PORTADA =====
|
# ===== PORTADA =====
|
||||||
elements.append(Spacer(1, 10*mm))
|
elements.append(Spacer(1, 10*mm))
|
||||||
|
|
||||||
# Logo principal (si existe)
|
# Función helper para cargar y dimensionar logos
|
||||||
if logo_url_to_use:
|
def load_logo(logo_url, max_width_mm=45, max_height_mm=35):
|
||||||
|
"""Carga un logo desde URL y retorna objeto Image con dimensiones ajustadas"""
|
||||||
|
if not logo_url:
|
||||||
|
return None
|
||||||
try:
|
try:
|
||||||
print(f"🔍 Intentando cargar logo desde: {logo_url_to_use}")
|
print(f"🔍 Cargando logo desde: {logo_url}")
|
||||||
logo_resp = requests.get(logo_url_to_use, timeout=10)
|
logo_resp = requests.get(logo_url, timeout=10)
|
||||||
print(f"📡 Respuesta del servidor: {logo_resp.status_code}")
|
print(f"📡 Respuesta: {logo_resp.status_code}")
|
||||||
|
|
||||||
if logo_resp.status_code == 200:
|
if logo_resp.status_code == 200:
|
||||||
logo_bytes = BytesIO(logo_resp.content)
|
logo_bytes = BytesIO(logo_resp.content)
|
||||||
# Crear imagen con tamaño máximo, manteniendo proporciones
|
|
||||||
logo_img = RLImage(logo_bytes)
|
logo_img = RLImage(logo_bytes)
|
||||||
|
|
||||||
# Ajustar tamaño manteniendo aspect ratio (máximo 50mm de ancho)
|
# Ajustar tamaño manteniendo aspect ratio
|
||||||
aspect = logo_img.imageHeight / float(logo_img.imageWidth)
|
aspect = logo_img.imageHeight / float(logo_img.imageWidth)
|
||||||
logo_width = 50*mm
|
logo_width = max_width_mm * mm
|
||||||
logo_height = logo_width * aspect
|
logo_height = logo_width * aspect
|
||||||
|
|
||||||
# Si la altura es muy grande, ajustar por altura
|
# Si la altura excede el máximo, ajustar por altura
|
||||||
if logo_height > 40*mm:
|
if logo_height > max_height_mm * mm:
|
||||||
logo_height = 40*mm
|
logo_height = max_height_mm * mm
|
||||||
logo_width = logo_height / aspect
|
logo_width = logo_height / aspect
|
||||||
|
|
||||||
logo_img.drawWidth = logo_width
|
logo_img.drawWidth = logo_width
|
||||||
logo_img.drawHeight = logo_height
|
logo_img.drawHeight = logo_height
|
||||||
|
|
||||||
logo_table = Table([[logo_img]], colWidths=[180*mm])
|
print(f"✅ Logo cargado ({logo_width/mm:.1f}mm x {logo_height/mm:.1f}mm)")
|
||||||
logo_table.setStyle(TableStyle([
|
return logo_img
|
||||||
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
|
|
||||||
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
|
|
||||||
]))
|
|
||||||
elements.append(logo_table)
|
|
||||||
elements.append(Spacer(1, 5*mm))
|
|
||||||
print(f"✅ Logo cargado correctamente ({logo_width/mm:.1f}mm x {logo_height/mm:.1f}mm)")
|
|
||||||
else:
|
else:
|
||||||
print(f"❌ Error HTTP al cargar logo: {logo_resp.status_code}")
|
print(f"❌ Error HTTP: {logo_resp.status_code}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"⚠️ Error cargando logo: {e}")
|
print(f"⚠️ Error cargando logo: {e}")
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Cargar ambos logos
|
||||||
|
company_logo = load_logo(company_logo_url, max_width_mm=50, max_height_mm=35)
|
||||||
|
checklist_logo = load_logo(checklist_logo_url, max_width_mm=50, max_height_mm=35)
|
||||||
|
|
||||||
|
# Crear tabla con logos en los extremos
|
||||||
|
logo_row = []
|
||||||
|
|
||||||
|
# Logo empresa (izquierda)
|
||||||
|
if company_logo:
|
||||||
|
logo_row.append(company_logo)
|
||||||
|
else:
|
||||||
|
logo_row.append(Paragraph("", styles['Normal'])) # Espacio vacío
|
||||||
|
|
||||||
|
# Espaciador central
|
||||||
|
logo_row.append(Paragraph("", styles['Normal']))
|
||||||
|
|
||||||
|
# Logo checklist (derecha)
|
||||||
|
if checklist_logo:
|
||||||
|
logo_row.append(checklist_logo)
|
||||||
|
else:
|
||||||
|
logo_row.append(Paragraph("", styles['Normal'])) # Espacio vacío
|
||||||
|
|
||||||
|
# Crear tabla con logos
|
||||||
|
logo_table = Table([logo_row], colWidths=[60*mm, 60*mm, 60*mm])
|
||||||
|
logo_table.setStyle(TableStyle([
|
||||||
|
('ALIGN', (0, 0), (0, 0), 'LEFT'), # Logo empresa a la izquierda
|
||||||
|
('ALIGN', (1, 0), (1, 0), 'CENTER'), # Centro vacío
|
||||||
|
('ALIGN', (2, 0), (2, 0), 'RIGHT'), # Logo checklist a la derecha
|
||||||
|
('VALIGN', (0, 0), (-1, -1), 'TOP'),
|
||||||
|
]))
|
||||||
|
elements.append(logo_table)
|
||||||
|
elements.append(Spacer(1, 5*mm))
|
||||||
|
|
||||||
# Título con diseño moderno
|
# Título con diseño moderno
|
||||||
elements.append(Paragraph("📋 INFORME DE INSPECCIÓN VEHICULAR", title_style))
|
elements.append(Paragraph("📋 INFORME DE INSPECCIÓN VEHICULAR", title_style))
|
||||||
|
|||||||
Reference in New Issue
Block a user