import sys; sys.path.insert(0, '/tmp/manuales')
from manual_lib import *

c = []
c += [H1('1. El perfil Administrador'),
      P('El Administrador (Admon) tiene acceso a toda la operación de recepción y, además, a la gestión de usuarios, la edición y anulación de registros, '
        'los traslados, el módulo de apartamentos con el portal de propietarios, las manillas y los reportes.'),
      P('Todo el trabajo diario de recepción (check-in, acompañantes, check-out, visitantes, empleados y paquetes) se explica en el '
        '<b>Manual de Recepción</b>. Este manual cubre solo lo propio del Administrador.'),
      H2('Perfiles del sistema'),
      *tabla(['Perfil', 'Qué puede hacer'], [
          ['Soporte', 'Todo lo del Administrador, más la pantalla de Configuración (nombre de la entidad, logo, SIRE, correo, casilla de manilla).'],
          ['Administrador (Admon)', 'Toda la operación, usuarios, edición, anulación y traslado, apartamentos y portal de propietarios, reportes.'],
          ['Funcionario Lobby', 'Operación de recepción: check-in, acompañantes, check-out, visitantes, empleados, paquetes, consultas.'],
          ['Operador de Garita', 'Registro y salida de empleados y visitantes, y paquetes.'],
          ['Operador zona común', 'Reservas y control de zonas comunes.'],
      ], [0.3, 0.7]),
      caja('Cada perfil ve solo sus opciones de menú, y el sistema lo verifica también en el servidor: aunque alguien conozca la dirección de una página, '
           'si su perfil no tiene permiso recibe "Acceso denegado".', 'nota')]
c += [H1('2. Usuarios del sistema'),
      P('Menú de su nombre (arriba a la derecha) › <b>Usuarios</b>.'),
      captura('usuarios', 'Listado de usuarios del sistema.'),
      H2('Crear un usuario'),
      pasos(['Pulse <b>Nuevo usuario</b>.',
             'Diligencie tipo y número de identificación, rol, nombres, apellidos, usuario de ingreso, contraseña, dirección y correo.',
             'Indique si el usuario queda <b>Bloqueado</b> (NO para que pueda ingresar).',
             'Pulse <b>Crear usuario</b>.']),
      captura('usuario_nuevo', 'Ventana de nuevo usuario.', 0.5),
      H2('Editar, bloquear o eliminar'),
      P('En la columna <b>Acciones</b>: el primer botón edita (datos, rol, contraseña o bloqueo) y el segundo elimina. '
        'Para retirar temporalmente a alguien, prefiera <b>bloquear</b> en lugar de eliminar: se conserva el historial de lo que hizo.'),
      caja('Las contraseñas se guardan cifradas (bcrypt): nadie, ni siquiera el Administrador, puede verlas. Si un usuario la olvida, asígnele una nueva. '
           'Use contraseñas de al menos 10 caracteres con letras y números, y una distinta por persona.', 'ok'),
      caja('Solo un usuario <b>Soporte</b> puede crear, editar o eliminar a otro usuario Soporte.', 'nota')]
c += [H1('3. Editar, anular y trasladar registros'),
      H2('Editar un check-in'),
      P('Menú <b>Edición › Check-in</b>. Elija el registro y pulse <b>Buscar</b>. Puede modificar apartamento, vehículo, parqueo, ocupación y fecha de salida, '
        'y los datos de cada huésped del registro (tipo y número de documento, país, ciudad, nombres, apellidos, salida y observaciones).'),
      captura('edit_checkin', 'Edición de un registro.'),
      caja('Por seguridad, la <b>fecha de ingreso</b> no se puede modificar desde ningún perfil.', 'aviso'),
      H2('Anular un registro'),
      P('En la edición del registro, o en Check-out, pulse <b>ANULAR</b> y confirme. Un registro anulado deja de contar en ocupación y reportes. '
        'Para habilitarlo de nuevo, pulse el mismo botón y confirme.'),
      H2('Trasladar de apartamento'),
      P('En Check-out, con el registro seleccionado, pulse <b>TRASLADO</b>, elija el apartamento de destino y la fecha de salida. '
        'El sistema crea <b>un nuevo número de registro</b> para la estadía trasladada.'),
      H2('Editar huéspedes, visitantes y empleados'),
      P('Menú <b>Edición › Huésped(es), Visitantes, Empleados</b>. Permite corregir datos y bloquear personas con una observación puntual.')]
c += [H1('4. Apartamentos y portal de propietarios'),
      P('Menú <b>Edición › Apartamento</b> (o <b>Ingresos › Ingreso de apartamento</b>, que abre el mismo módulo con el formulario de nuevo apartamento).'),
      captura('apartamentos', 'Módulo de apartamentos.'),
      P('Arriba verá los indicadores (apartamentos, con acceso al portal, usuarios del portal, sin correo, con token TRA y bloqueados), el buscador, el filtro por torre '
        'y los filtros rápidos <b>Sin usuario</b>, <b>Sin correo</b>, <b>Bloqueados</b> y <b>Sin token TRA</b>.'),
      H2('Crear o editar un apartamento'),
      pasos(['Pulse <b>Nuevo apartamento</b> o <b>Editar</b> en la fila.',
             'Diligencie número (obligatorio y único), torre, vista, parqueadero, capacidad, habitaciones, adicionales, propietario, tipo de administración, '
             'registro de turismo y su vigencia, bloqueo y observación.',
             'Pegue el <b>Token TRA</b> si ya lo tiene (ver la sección 5).',
             'Pulse <b>Guardar</b>.']),
      caja('No se puede eliminar un apartamento con una estadía activa, ni cambiar el número de uno que ya tiene reservas registradas. '
           'Al eliminar un apartamento con usuarios del portal, el sistema pide confirmación y elimina también esos usuarios con sus permisos.', 'aviso'),
      H2('Eliminar varios apartamentos a la vez'),
      pasos(['Marque la casilla de cada apartamento, o la casilla del encabezado para seleccionar <b>todos los que muestra el filtro actual</b> '
             '(por ejemplo, una torre completa o el resultado de una búsqueda).',
             'Pulse <b>Eliminar seleccionados</b> en la barra azul.',
             'Revise el resumen: cuántos se eliminarán, cuántos usuarios del portal se perderán y cuáles quedan excluidos por tener estadía activa.',
             'Escriba <b>ELIMINAR</b> y pulse <b>Eliminar definitivamente</b>.']),
      caja('La acción no se puede deshacer y arrastra los usuarios del portal de esos apartamentos con sus permisos. Los apartamentos con estadía activa '
           'nunca se eliminan, y el historial de reservas se conserva. Antes de un borrado grande, pida al Soporte una copia de respaldo de la base de datos.', 'peligro'),
      H2('Usuarios del portal de propietarios'),
      P('Botón <b>Usuarios</b> en la fila del apartamento. Cada apartamento puede tener varios usuarios (propietario, administrador del apartamento, autorizado).'),
      captura('portal_usuarios', 'Usuarios del portal de un apartamento, con sus permisos.'),
      *vinetas(['<b>Agregar usuario / Editar:</b> nombres, identificación, uno o varios correos separados por punto y coma, rol, observación, bloqueo y notificaciones automáticas.',
                '<b>Permisos en el portal:</b> interruptores por módulo (reservas, reportes, circulares, registros, usuarios) y por opción. Si apaga un módulo, sus opciones se desactivan.',
                '<b>Cambiar clave:</b> escriba o genere una clave (mínimo 4 caracteres, sin espacios; se recomiendan 8 o más) y, si quiere, envíela por correo.',
                '<b>Enviar clave:</b> genera una clave temporal nueva y la envía por correo. La clave anterior deja de funcionar. Si el correo falla, la clave no se cambia.',
                '<b>Bloquear / Eliminar:</b> retira el acceso al portal.']),
      caja('El primer correo del usuario recibe la clave; los demás reciben copia. La clave se guarda en el mismo formato que usa el portal, por lo que el propietario puede ingresar de inmediato.', 'nota'),
      H2('Importar apartamentos desde Excel'),
      pasos(['Descargue la <b>Plantilla Excel</b>, o use <b>Exportar</b> para editar los apartamentos actuales.',
             'Complete una fila por apartamento. Solo <b>num_apto</b> es obligatorio; las columnas <i>usuario_</i> crean el acceso al portal.',
             'Pulse <b>Importar Excel</b> y elija el archivo (.xlsx o .csv, máximo 5 MB).',
             'Revise la <b>vista previa</b>: filas nuevas, actualizaciones y errores explicados por fila. Las filas con error no se guardan.',
             'Elija las opciones (actualizar existentes, crear usuarios del portal, enviar clave) y pulse <b>Importar</b>.']),
      captura('importar', 'Vista previa de una importación.'),
      caja('Al actualizar apartamentos existentes, una celda vacía <b>no borra</b> el dato actual: solo se cambian las celdas con valor.', 'ok'),
      H2('Cargar claves del portal desde el Excel'),
      P('La plantilla incluye la columna <b>usuario_clave</b>, que guarda la clave de acceso al portal en la ficha del usuario:'),
      *vinetas(['Si el usuario es nuevo, se crea con esa clave.',
                'Si el usuario ya existe (mismo correo en ese apartamento), se le actualiza la clave.',
                'La clave debe tener al menos 4 caracteres y no puede contener espacios; si no, la fila se marca con error y no se guarda.',
                'Con la casilla <b>Enviar clave por correo</b>, se envía exactamente la clave del archivo, no una temporal.',
                'La columna nunca se llena al exportar: las claves guardadas no se pueden leer.']),
      caja('El archivo de Excel queda con las claves escritas en texto plano: guárdelo en un lugar seguro o bórrelo después de importar.', 'aviso')]
c += [H2('Bloqueo de zonas comunes'),
      P('La columna <b>Zonas comunes</b> del listado indica si el apartamento puede reservar zonas comunes (piscina, zonas húmedas y demás áreas). '
        'Con el interruptor en <font color="#B42318"><b>Bloqueadas</b></font>, ni sus huéspedes ni sus propietarios pueden reservar: la pantalla de reserva muestra un aviso '
        'y deshabilita el formulario, y el sistema rechaza cualquier intento de reserva.'),
      *vinetas(['Cambie el bloqueo directamente en el listado (pide confirmación al bloquear) o en el formulario del apartamento (campo <b>Bloqueo de zonas comunes</b>).',
                'El filtro <b>Zonas bloqueadas</b> muestra los apartamentos bloqueados.',
                'En la plantilla de Excel, la columna <b>bloqueo_zona</b> acepta SI o NO.']),
      caja('Este bloqueo es distinto del campo <b>Bloqueado</b> del apartamento: solo impide la reserva de zonas comunes; el apartamento sigue operando normalmente.', 'nota')]
c += [H1('5. Token TRA'),
      P('La columna <b>Token TRA</b> guarda por apartamento el token de la Tarjeta de Registro Hotelero exigida en Colombia. En el listado solo se ve si está '
        '<b>Configurado</b> o <b>Pendiente</b>; el token nunca se muestra en pantalla.'),
      captura('apto_editar', 'Formulario del apartamento con el campo Token TRA.'),
      *vinetas(['Para cargarlo, edite el apartamento y pegue el token. Los espacios y saltos de línea se quitan solos.',
                'Para conservar el token guardado, deje el campo vacío al editar.',
                'Para quitarlo, marque <b>Borrar el token guardado</b>.',
                'También se puede cargar en bloque con la columna <b>token_tra</b> de la plantilla de Excel.',
                'El filtro <b>Sin token TRA</b> muestra los apartamentos pendientes.']),
      caja('Si la columna Token TRA no aparece, la base de datos aún no la tiene: un usuario Soporte la crea en Configuración › Base de datos.', 'nota')]
c += [H1('6. Probador de correo'),
      P('Botón <b>Probador de correo</b> del módulo de apartamentos, o <b>Probar correo</b> en la fila de un apartamento (trae los correos de sus usuarios).'),
      captura('probador', 'Resultado del probador de correo.'),
      *tabla(['Revisión', 'Qué indica'], [
          ['Formato', 'Que la dirección esté bien escrita.'],
          ['Dominio', 'Que el dominio del correo tenga servidor de correo (por ejemplo, que gmail.com exista).'],
          ['Listas SendGrid', 'Si la dirección rebotó antes, fue bloqueada, es inválida o reportó spam. Mientras esté en una lista, SendGrid no le entrega mensajes.'],
          ['Envío de prueba', '"Aceptado (202)" significa que SendGrid recibió el mensaje para entregarlo, con su identificador. Si el buzón no existe, el rebote aparece en unos minutos.'],
      ], [0.25, 0.75]),
      caja('Límite: 20 envíos de prueba cada 10 minutos por sesión. Si un correo está en una lista de supresión, no se le envía la prueba; '
           'el Soporte puede retirarlo de la lista desde la cuenta de SendGrid.', 'nota')]
c += [H1('7. Reportes, migración y manillas'),
      H2('Reportes'),
      *vinetas(['<b>Reportes › Reporte por apartamento:</b> elija apartamento y rango de fechas, y pulse Buscar.',
                '<b>Reporte edificio, estadístico, de registros, de visitas y de empleados.</b>',
                '<b>Huésped en casa</b> y <b>Checkout today</b>: quién está alojado y quién sale hoy.']),
      captura('reporte_apto', 'Filtro del reporte por apartamento.'),
      H2('Migración (SIRE)'),
      P('<b>Consultas › Migración</b> y <b>Migración salida</b> generan el archivo para el reporte a Migración Colombia. '
        'Los códigos del establecimiento y de la ciudad los configura el perfil Soporte.'),
      H2('Manillas'),
      P('Menú <b>Manillas</b>: crear rangos de manillas, consultar manillas por color o por apartamento y sus reportes. '
        'Si la copropiedad no usa manillas, el Soporte puede ocultar la casilla en todos los formularios; los registros se guardan con manilla 0000.')]
c += [H1('8. Buenas prácticas de seguridad'),
      *vinetas(['Cree un usuario por persona. No comparta usuarios.',
                'Bloquee de inmediato a quien deje de trabajar en la copropiedad.',
                'Revise periódicamente los usuarios activos y sus perfiles.',
                'Cierre la sesión al terminar el turno.',
                'Los datos de huéspedes son personales: úselos solo para la operación y el reporte de ley.',
                'Ante cualquier comportamiento extraño del sistema, avise al Soporte.']),
      caja('El sistema bloquea un usuario por 15 minutos tras 5 intentos fallidos de ingreso, y cierra la sesión tras varias horas sin actividad.', 'nota')]

construir(sys.argv[1], 'Administrador', 'Perfil Administrador (Admon)',
          'Gestión de usuarios, edición, anulación y traslado de registros, apartamentos y portal de propietarios, importación desde Excel, token TRA, probador de correo y reportes.', c)
print('ok')
