From 76319096065aff838084f3942aebae75f8eb0e6f Mon Sep 17 00:00:00 2001 From: Kevin_Ramirez Date: Wed, 27 May 2026 09:12:13 -0500 Subject: [PATCH] feat: generador de Manual de Instalacion (docx) Script Python que genera Manual_Instalacion.docx con: - Portada y requisitos - Instalacion paso a paso (ejecutar como administrador) - Configuracion .env - Primer uso y FAQ Co-Authored-By: Claude Opus 4.7 (1M context) --- app/generar_manual_instalacion.py | 429 ++++++++++++++++++++++++++++++ 1 file changed, 429 insertions(+) create mode 100755 app/generar_manual_instalacion.py diff --git a/app/generar_manual_instalacion.py b/app/generar_manual_instalacion.py new file mode 100755 index 0000000..503b379 --- /dev/null +++ b/app/generar_manual_instalacion.py @@ -0,0 +1,429 @@ +""" +Genera el manual de instalación y primeros pasos de Utilerías RECON 2. +""" +from docx import Document +from docx.shared import Pt, RGBColor, Cm +from docx.enum.text import WD_ALIGN_PARAGRAPH +from docx.oxml.ns import qn +from docx.oxml import OxmlElement +import datetime, os + +doc = Document() + +for sec in doc.sections: + sec.top_margin = Cm(2.5) + sec.bottom_margin = Cm(2.5) + sec.left_margin = Cm(2.2) + sec.right_margin = Cm(2.2) + +style = doc.styles['Normal'] +style.font.name = 'Calibri' +style.font.size = Pt(11) + + +# ── Helpers ────────────────────────────────────────────────────────────────── +def h1(text): + p = doc.add_heading(text, level=1) + for r in p.runs: r.font.color.rgb = RGBColor(0x15, 0x65, 0xC0) + +def h2(text): + p = doc.add_heading(text, level=2) + for r in p.runs: r.font.color.rgb = RGBColor(0x1E, 0x88, 0xE5) + +def h3(text): + p = doc.add_heading(text, level=3) + for r in p.runs: r.font.color.rgb = RGBColor(0x42, 0xA5, 0xF5) + +def parr(text, bold=False): + p = doc.add_paragraph() + r = p.add_run(text) + r.bold = bold + return p + +def code_block(text): + p = doc.add_paragraph() + p.paragraph_format.left_indent = Cm(0.4) + r = p.add_run(text) + r.font.name = 'Consolas' + r.font.size = Pt(9.5) + pPr = p._p.get_or_add_pPr() + shd = OxmlElement('w:shd') + shd.set(qn('w:val'), 'clear') + shd.set(qn('w:color'), 'auto') + shd.set(qn('w:fill'), 'F0F0F0') + pPr.append(shd) + return p + +def bullet(text, level=0): + p = doc.add_paragraph(text, style='List Bullet') + p.paragraph_format.left_indent = Cm(0.6 + level * 0.6) + return p + +def numbered(text): + p = doc.add_paragraph(text, style='List Number') + p.paragraph_format.left_indent = Cm(0.6) + return p + +def nota(titulo, text): + p = doc.add_paragraph() + p.paragraph_format.left_indent = Cm(0.4) + pPr = p._p.get_or_add_pPr() + shd = OxmlElement('w:shd') + shd.set(qn('w:val'), 'clear'); shd.set(qn('w:color'), 'auto') + shd.set(qn('w:fill'), 'FFF8E1') + pPr.append(shd) + r = p.add_run(titulo + ': '); r.bold = True + r.font.color.rgb = RGBColor(0xE6, 0x5C, 0x00) + p.add_run(text) + +def alerta(titulo, text): + p = doc.add_paragraph() + p.paragraph_format.left_indent = Cm(0.4) + pPr = p._p.get_or_add_pPr() + shd = OxmlElement('w:shd') + shd.set(qn('w:val'), 'clear'); shd.set(qn('w:color'), 'auto') + shd.set(qn('w:fill'), 'FFEBEE') + pPr.append(shd) + r = p.add_run(titulo + ': '); r.bold = True + r.font.color.rgb = RGBColor(0xC6, 0x28, 0x28) + p.add_run(text) + +def tip(titulo, text): + p = doc.add_paragraph() + p.paragraph_format.left_indent = Cm(0.4) + pPr = p._p.get_or_add_pPr() + shd = OxmlElement('w:shd') + shd.set(qn('w:val'), 'clear'); shd.set(qn('w:color'), 'auto') + shd.set(qn('w:fill'), 'E8F5E9') + pPr.append(shd) + r = p.add_run(titulo + ': '); r.bold = True + r.font.color.rgb = RGBColor(0x2E, 0x7D, 0x32) + p.add_run(text) + +def table_simple(headers, rows, col_widths_cm=None): + t = doc.add_table(rows=1 + len(rows), cols=len(headers)) + t.style = 'Light Grid Accent 1' + hdr = t.rows[0].cells + for i, h in enumerate(headers): + hdr[i].text = h + for p in hdr[i].paragraphs: + for r in p.runs: + r.bold = True + r.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF) + tcPr = hdr[i]._tc.get_or_add_tcPr() + shd = OxmlElement('w:shd') + shd.set(qn('w:val'), 'clear') + shd.set(qn('w:fill'), '1565C0') + tcPr.append(shd) + for r_idx, row in enumerate(rows, start=1): + cells = t.rows[r_idx].cells + for c_idx, val in enumerate(row): + cells[c_idx].text = str(val) + if col_widths_cm: + for i, w in enumerate(col_widths_cm): + for row in t.rows: + row.cells[i].width = Cm(w) + return t + + +# ── PORTADA ─────────────────────────────────────────────────────────────────── +title = doc.add_paragraph() +title.alignment = WD_ALIGN_PARAGRAPH.CENTER +r = title.add_run('\n\n\nSistema de Utilerías RECON 2') +r.bold = True; r.font.size = Pt(34); r.font.color.rgb = RGBColor(0x15, 0x65, 0xC0) + +sub = doc.add_paragraph() +sub.alignment = WD_ALIGN_PARAGRAPH.CENTER +r = sub.add_run('Guía de Instalación y Primeros Pasos') +r.font.size = Pt(20); r.font.color.rgb = RGBColor(0x42, 0xA5, 0xF5) + +p = doc.add_paragraph() +p.alignment = WD_ALIGN_PARAGRAPH.CENTER +r = p.add_run(f'\n\nVersión {datetime.date.today().isoformat()}') +r.font.size = Pt(12); r.italic = True + +doc.add_page_break() + + +# ── ÍNDICE ──────────────────────────────────────────────────────────────────── +h1('Contenido') +for item in [ + '1. Requisitos previos', + '2. Instalación paso a paso', + '3. Configuración inicial (.env)', + '4. Primer uso de la aplicación', + '5. Preguntas frecuentes', +]: + doc.add_paragraph(item) + +doc.add_page_break() + + +# ── 1. REQUISITOS ───────────────────────────────────────────────────────────── +h1('1. Requisitos previos') +parr('Antes de instalar, verifica que la computadora cumple con lo siguiente:') + +table_simple( + ['Requisito', 'Detalle'], + [ + ['Sistema operativo', 'Windows 10 / Windows 11 (64 bits)'], + ['Permisos', 'Cuenta con permisos de Administrador local'], + ['ODBC Driver', 'Microsoft ODBC Driver 17 o 18 for SQL Server'], + ['Acceso a red', 'Conexión al servidor donde está la base de datos SCAII'], + ['Espacio en disco', 'Mínimo 500 MB libres en la unidad de instalación'], + ], + col_widths_cm=[4.5, 11] +) + +doc.add_paragraph() +alerta( + 'IMPORTANTE — Permisos de Administrador', + 'La aplicación DEBE instalarse y ejecutarse como Administrador. ' + 'Sin este permiso, el instalador no podrá registrar los componentes necesarios ' + 'y la aplicación fallará al intentar conectarse a la base de datos.' +) + +doc.add_paragraph() +h3('Cómo verificar si tienes el ODBC Driver instalado') +numbered('Presiona Windows + R, escribe odbcad32 y presiona Enter') +numbered('En la pestaña "Controladores" busca "ODBC Driver 17 for SQL Server" o "ODBC Driver 18 for SQL Server"') +numbered('Si no aparece, solicita al área de sistemas que lo instale antes de continuar') + + +# ── 2. INSTALACIÓN ──────────────────────────────────────────────────────────── +doc.add_page_break() +h1('2. Instalación paso a paso') + +alerta( + 'Ejecutar como Administrador', + 'Todos los pasos de esta sección deben realizarse con permisos de Administrador. ' + 'Si no lo haces, la instalación puede completarse pero la aplicación no funcionará correctamente.' +) + +doc.add_paragraph() +h2('Paso 1 — Obtener el instalador') +parr('El archivo instalador tiene un nombre similar a:') +code_block('UtileriasReconV2_Setup.exe') +parr('Solicítalo al área técnica o descárgalo de la ubicación que te indiquen.') + +doc.add_paragraph() +h2('Paso 2 — Ejecutar el instalador como Administrador') +numbered('Localiza el archivo UtileriasReconV2_Setup.exe en tu computadora') +numbered('Haz clic derecho sobre el archivo') +numbered('Selecciona "Ejecutar como administrador"') +numbered('Si Windows muestra una ventana de Control de Cuentas de Usuario (UAC), haz clic en "Sí"') + +doc.add_paragraph() +nota( + 'Clic derecho → Ejecutar como administrador', + 'Es fundamental este paso. Si haces doble clic normal y tu cuenta no es administrador, ' + 'la instalación puede parecer exitosa pero la app fallará al abrir.' +) + +doc.add_paragraph() +h2('Paso 3 — Seguir el asistente de instalación') +numbered('Se abre el asistente de instalación. Haz clic en "Siguiente"') +numbered('Lee y acepta los términos de uso, luego haz clic en "Siguiente"') +numbered('Elige la carpeta de instalación (se recomienda dejar la carpeta predeterminada)') +code_block('C:\\Program Files\\UtileriasReconV2\\') +numbered('Haz clic en "Instalar" y espera a que termine el proceso (tarda aproximadamente 1-2 minutos)') +numbered('Al terminar, haz clic en "Finalizar"') + +tip( + 'Carpeta de instalación', + 'Si instalas en una ruta diferente a la predeterminada, anota la ruta. ' + 'La necesitarás para el paso de configuración.' +) + +doc.add_paragraph() +h2('Paso 4 — Verificar la instalación') +parr('Al finalizar, deberías ver en la carpeta de instalación los siguientes archivos principales:') +table_simple( + ['Archivo / Carpeta', 'Descripción'], + [ + ['UtileriasReconV2.exe', 'El ejecutable principal de la aplicación'], + ['app.ipynb', 'El notebook con toda la lógica de la app'], + ['.env.example', 'Plantilla de configuración — debes renombrarlo a .env'], + ['_internal/', 'Carpeta con dependencias internas (no modificar)'], + ], + col_widths_cm=[5, 10] +) + + +# ── 3. CONFIGURACIÓN ───────────────────────────────────────────────────────── +doc.add_page_break() +h1('3. Configuración inicial (.env)') + +parr( + 'La aplicación usa un archivo llamado .env para saber a qué servidor conectarse ' + 'y con qué credenciales. Este archivo NO viene incluido en el instalador por seguridad — ' + 'debes crearlo tú a partir de la plantilla.' +) + +doc.add_paragraph() +h2('Crear el archivo .env') +numbered('Ve a la carpeta de instalación') +numbered('Localiza el archivo .env.example') +numbered('Copia ese archivo y renombra la copia como .env (sin el .example)') +numbered('Abre el archivo .env con el Bloc de notas o cualquier editor de texto') +numbered('Modifica los valores según los datos de tu servidor:') + +doc.add_paragraph() +code_block( + '# Servidor SCAII (SQL Server)\n' + 'SCAII_SERVER=nombre-o-ip-de-tu-servidor\n' + 'SCAII_USER=tu_usuario\n' + 'SCAII_PASSWORD=tu_contraseña\n' + '\n' + '# Autenticación Windows (opcional)\n' + '# Si tu servidor usa Windows Auth en lugar de usuario/contraseña,\n' + '# cambia el valor a "yes"\n' + 'SCAII_TRUSTED=no\n' + '\n' + '# Ruta donde están los archivos .asc del DataStage\n' + 'DATASTAGE_PATH=C:\\ruta\\a\\tus\\archivos\\asc\n' +) + +nota( + 'Archivo sensible', + 'El archivo .env contiene contraseñas. No lo compartas por correo ni lo subas a ningún ' + 'repositorio. Mantenlo solo en la computadora de trabajo.' +) + +doc.add_paragraph() +h2('Autenticación Windows vs. usuario y contraseña') +table_simple( + ['Escenario', 'Configuración en .env'], + [ + ['Tu servidor pide usuario y contraseña de SQL Server', + 'SCAII_TRUSTED=no\nSCAII_USER=sa\nSCAII_PASSWORD=TuContraseña'], + ['Tu servidor usa Windows Authentication (credenciales de Windows)', + 'SCAII_TRUSTED=yes\n(SCAII_USER y SCAII_PASSWORD se ignoran)'], + ], + col_widths_cm=[6, 9] +) + + +# ── 4. PRIMER USO ───────────────────────────────────────────────────────────── +doc.add_page_break() +h1('4. Primer uso de la aplicación') + +alerta( + 'Ejecutar como Administrador', + 'Cada vez que abras la aplicación, hazlo con clic derecho → ' + '"Ejecutar como administrador". De lo contrario puede fallar la conexión a la base de datos.' +) + +doc.add_paragraph() +h2('Abrir la aplicación') +numbered('Localiza el acceso directo en el escritorio o ve a la carpeta de instalación') +numbered('Haz clic derecho sobre UtileriasReconV2.exe') +numbered('Selecciona "Ejecutar como administrador"') +numbered('Aparece una ventana negra de consola — NO la cierres, es normal') +numbered('Después de unos segundos, tu navegador (Edge o Chrome) abre automáticamente la aplicación') + +tip( + 'Si el navegador no abre solo', + 'Escribe manualmente en la barra de direcciones: http://127.0.0.1:8866/' +) + +doc.add_paragraph() +nota( + 'La consola negra', + 'La ventana negra debe permanecer abierta todo el tiempo que uses la aplicación. ' + 'Si la cierras, la app se apaga. Cuando termines de trabajar, primero cierra el ' + 'navegador y luego cierra la consola.' +) + +doc.add_paragraph() +h2('Verificar la conexión a la base de datos') +parr( + 'Al cargar la aplicación, en la parte superior verás una barra de estado. ' + 'Su color te indica si la conexión es correcta:' +) +table_simple( + ['Color de la barra', 'Significado'], + [ + ['Azul / Verde', 'Conexión exitosa. Puedes trabajar normalmente.'], + ['Rojo', 'Error de conexión. Revisa el archivo .env y que el servidor esté disponible.'], + ], + col_widths_cm=[4, 11] +) + +doc.add_paragraph() +h2('Navegar por las pestañas') +parr('La aplicación tiene varias pestañas en la parte superior. Cada una corresponde a una función:') +table_simple( + ['Pestaña', 'Para qué sirve'], + [ + ['Conexión / Config', 'Seleccionar la base de datos activa y ver el estado de la conexión'], + ['Descargas', 'Generar y complementar descargas de inventario contra facturas'], + ['Análisis de Saldos', 'Ver el estado del inventario: saldos, comparativos, exportar a Excel'], + ['Sustitutos NLP', 'Sugerir automáticamente números de parte similares'], + ['Descarga % KGS', 'Descargas basadas en porcentaje de peso (BOMs con cantidades en %)'], + ['DataStage', 'Cargar archivos .asc del SAAIM3 y generar estructuras SCAII'], + ['Estructuras SCAII', 'Generar los Excel de partidas y encabezados para importar en SCAII'], + ], + col_widths_cm=[4, 11] +) + + +# ── 5. FAQ ──────────────────────────────────────────────────────────────────── +doc.add_page_break() +h1('5. Preguntas frecuentes') + +h3('¿Por qué tengo que ejecutarlo como Administrador?') +parr( + 'La aplicación necesita permisos de administrador para dos cosas: ' + '(1) conectarse al servidor de SQL Server a través del driver ODBC, y ' + '(2) escribir los archivos temporales que genera Jupyter internamente. ' + 'Sin estos permisos, la app puede abrir visualmente pero falla al intentar ' + 'cualquier operación con la base de datos.' +) + +doc.add_paragraph() +h3('¿Puedo instalarla sin ser administrador?') +parr( + 'No. El instalador requiere privilegios de administrador para registrar los ' + 'componentes de Jupyter y el driver ODBC. Si no tienes estos permisos en tu ' + 'equipo, solicita al área de sistemas que haga la instalación.' +) + +doc.add_paragraph() +h3('La app abre pero dice "Error de conexión"') +bullet('Verifica que el archivo .env existe en la carpeta de instalación (no solo .env.example)') +bullet('Revisa que el servidor SCAII_SERVER sea correcto (nombre o IP)') +bullet('Confirma que el usuario y contraseña sean correctos') +bullet('Asegúrate de que el servidor SQL Server esté encendido y accesible desde tu red') +bullet('Si usas Windows Auth (SCAII_TRUSTED=yes), verifica que tu usuario de Windows tenga acceso al servidor') + +doc.add_paragraph() +h3('¿Cómo sé que la instalación fue exitosa?') +parr('Si puedes abrir la app como Administrador y la barra superior muestra azul o verde sin errores, ' + 'la instalación está correcta.') + +doc.add_paragraph() +h3('¿Tengo que instalarla cada vez que actualicen la app?') +parr( + 'Depende del tipo de actualización. Si el área técnica entrega un nuevo instalador ' + '(.exe de setup), sí hay que reinstalar. Si solo entregan un nuevo archivo app.ipynb, ' + 'basta con reemplazar ese archivo en la carpeta de instalación sin reinstalar todo.' +) + +doc.add_paragraph() +alerta( + 'Soporte', + 'Para cualquier problema de instalación o configuración que no esté cubierto en este manual, ' + 'contacta al área técnica de Aduanasoft.' +) + + +# ── GUARDAR ─────────────────────────────────────────────────────────────────── +out_path = 'Manual_Instalacion.docx' +try: + doc.save(out_path) +except PermissionError: + out_path = f'Manual_Instalacion_{datetime.datetime.now().strftime("%Y%m%d_%H%M%S")}.docx' + doc.save(out_path) + print('(El anterior estaba abierto en Word. Generado con nombre alternativo.)') +print(f'Manual generado: {os.path.abspath(out_path)}')