diff --git a/README.md b/README.md index 4a75b92..58fab68 100644 --- a/README.md +++ b/README.md @@ -10,16 +10,15 @@ A simple SQLite-based system for managing tablet lending and returns. - **Return Management**: Record when tablets are returned - **History Tracking**: Complete history of all loans and returns - **User Loans View**: See all tablets loaned to each user (demonstrates one-to-many relationship) -- **Non-Loanable Devices**: Track inventory devices that cannot be loaned (e.g., projectors, monitors) - **Project Notes**: Markdown editor for development documentation ## Files -- `minimal_app.py` - Interactive command-line application (includes non-loanable device management) +- `minimal_app.py` - Interactive command-line application - `test_app.py` - Test script that demonstrates functionality -- `tablets.db` - SQLite database (created automatically, includes non_loanable_devices table) -- `simple_app.py` - Web-based version (requires Flask, includes non-loanable device management) -- `app.py` - Alternative web version (requires Flask, includes non-loanable device management) +- `tablets.db` - SQLite database (created automatically) +- `simple_app.py` - Web-based version (requires Flask) +- `app.py` - Alternative web version (requires Flask) ## Quick Start @@ -145,7 +144,6 @@ python3 app.py - **Loan Tablet**: Loan a tablet to a user (with search for large datasets) - **User Loans**: View all tablets loaned to each user - demonstrates the **one-to-many relationship** (one user, multiple tablets) - **Loan History**: Complete history of all loan and return transactions -- **Non-Loanable Devices**: Manage inventory of devices that cannot be loaned (add, edit, delete, view) - **Project Management**: Markdown editor for development notes (saved to `notes_development/project_notes.md`) ## Database Backup @@ -155,17 +153,6 @@ To backup your data: cp tablets.db tablets_backup_$(date +%Y%m%d).db ``` -## Version Control - -This project uses Git for version control with the following structure: - -- `master` - Production-ready releases -- `develop` - Integration branch for features -- `feature/*` - Individual feature branches -- `hotfix/*` - Urgent bug fixes - -See `CONTRIBUTING.md` for detailed workflow and commit conventions. - ## License This is a simple educational project. Feel free to use and modify it as needed. \ No newline at end of file diff --git a/REQUIREMENTS.md b/REQUIREMENTS.md deleted file mode 100644 index f0c6929..0000000 --- a/REQUIREMENTS.md +++ /dev/null @@ -1,221 +0,0 @@ -# Requisitos del Sistema de Gestión de Préstamos de Tablets - -## Descripción General - -El sistema debe permitir la gestión del préstamo y devolución de dispositivos tablets entre un inventario y un conjunto de usuarios. El enfoque principal es el seguimiento del estado de cada dispositivo y su relación con los usuarios que los han tomado prestados. - ---- -## Requisitos Faltantes - -### Gestión de dispositivos no prestables - -✅ **IMPLEMENTADO** - El sistema ahora permite: -- Registrar nuevos dispositivos no prestables en un inventario separado (tabla `non_loanable_devices`) -- Gestionar dispositivos no prestables a través de: - - Interfaz web (app.py): /non_loanable_devices, /add_non_loanable_device, /edit_non_loanable_device, /delete_non_loanable_device - - Interfaz CLI (minimal_app.py): Opciones 8, 9, 10 del menú -- La implementación utiliza una tabla separada en la misma base de datos con los siguientes campos: - - brand, model, serial_number (único), device_type, location, status, notes, purchase_date, purchase_cost - -## Requisitos Funcionales - -### Gestión de Dispositivos - -El sistema debe permitir: -- Registrar nuevos dispositivos en el inventario -- Identificar cada dispositivo de manera única -- Almacenar información descriptiva de cada dispositivo (marca, modelo, número de serie) -- Consultar el estado actual de cada dispositivo (disponible, prestado) - -### Gestión de Usuarios - -El sistema debe permitir: -- Registrar nuevos usuarios -- Identificar cada usuario de manera única -- Almacenar información de contacto básica (nombre, identificación) -- Consultar la información de los usuarios registrados - -### Gestión de Préstamos - -El sistema debe permitir: -- Asignar un dispositivo disponible a un usuario -- Registrar la fecha y hora del préstamo -- Registrar la fecha y hora de la devolución -- Consultar el historial de préstamos de un dispositivo -- Consultar el historial de préstamos de un usuario -- Visualizar todos los dispositivos actualmente prestados - -### Consulta y Reportes - -El sistema debe permitir: -- Buscar dispositivos por cualquier atributo (marca, modelo, número de serie) -- Buscar usuarios por cualquier atributo (nombre, identificación) -- Filtrar préstamos por estado (activos, finalizados) -- Filtrar préstamos por dispositivo -- Filtrar préstamos por usuario -- Ver el historial completo de préstamos y devoluciones - ---- - -## Modelo de Datos - -### Entidades Principales - -1. **Dispositivo** - - Identificador único - - Marca - - Modelo - - Número de serie (único) - - Estado (disponible, prestado) - -2. **Usuario** - - Identificador único - - Nombre - - Identificación (única) - -3. **Préstamo** - - Identificador único - - Dispositivo asociado - - Usuario asociado - - Fecha de préstamo - - Fecha de devolución (opcional) - - Estado (activo, finalizado) - -### Relaciones - -- Un **usuario** puede tener **múltiples préstamos** (relación uno a muchos) -- Un **dispositivo** solo puede estar en **un préstamo activo** a la vez -- Un **préstamo** relaciona exactamente un dispositivo con un usuario -- El historial de préstamos permite rastrear todos los movimientos de cada dispositivo - -### Reglas de Negocio - -1. Un dispositivo en estado "prestado" no puede ser prestado a otro usuario -2. Un préstamo finalizado debe registrar fecha de devolución -3. La identificación de dispositivos y usuarios debe ser única -4. Al devolver un dispositivo, este vuelve al estado "disponible" - ---- - -## Flujos de Trabajo - -### Registro de un Nuevo Dispositivo - -1. El sistema solicita la información del dispositivo (marca, modelo, número de serie) -2. El sistema valida que el número de serie no esté registrado -3. El sistema registra el dispositivo con estado "disponible" -4. El sistema confirma el registro - -### Registro de un Nuevo Usuario - -1. El sistema solicita la información del usuario (nombre, identificación) -2. El sistema valida que la identificación no esté registrada -3. El sistema registra el usuario -4. El sistema confirma el registro - -### Préstamo de un Dispositivo - -1. El sistema muestra los dispositivos disponibles -2. El usuario selecciona un dispositivo -3. El sistema muestra los usuarios registrados -4. El usuario selecciona un usuario -5. El sistema registra el préstamo con: - - Dispositivo seleccionado - - Usuario seleccionado - - Fecha y hora actual - - Estado "activo" -6. El sistema actualiza el estado del dispositivo a "prestado" -7. El sistema confirma el préstamo - -### Devolución de un Dispositivo - -1. El sistema muestra los préstamos activos -2. El usuario selecciona un préstamo -3. El sistema registra la fecha y hora de devolución -4. El sistema actualiza el estado del préstamo a "finalizado" -5. El sistema actualiza el estado del dispositivo a "disponible" -6. El sistema confirma la devolución - -### Consulta de Préstamos por Usuario - -1. El sistema muestra la lista de usuarios -2. El usuario selecciona un usuario -3. El sistema muestra: - - Dispositivos actualmente prestados (préstamos activos) - - Historial de préstamos pasados (opcional: expandible) -4. El sistema permite buscar por cualquier campo - ---- - -## Requisitos No Funcionales - -### Usabilidad - -- La interfaz debe permitir búsqueda eficiente en listas grandes (500+ elementos) -- La visualización de información debe ser clara y organizada -- Los estados deben ser fácilmente identificables -- Las acciones principales deben ser accesibles - -### Escalabilidad - -- El diseño debe soportar un crecimiento en el número de dispositivos y usuarios -- La búsqueda debe ser eficiente -- El historial debe ser consultable sin afectar el rendimiento - -### Mantenibilidad - -- La estructura de datos debe ser clara -- Las relaciones entre entidades deben estar bien definidas -- Los flujos de trabajo deben estar documentados - ---- - -## Diseño de Interfaz (Conceptual) - -### Vistas Principales - -1. **Vista de Inventario** - - Lista de dispositivos - - Filtros por estado - - Búsqueda - -2. **Vista de Usuarios** - - Lista de usuarios - - Búsqueda - -3. **Vista de Préstamos Activos** - - Lista de préstamos en curso - - Filtros por dispositivo/usuario - - Acciones: devolver dispositivo - -4. **Vista de Historial** - - Lista completa de préstamos - - Filtros por fecha, usuario, dispositivo, estado - - Detalles de cada préstamo - -5. **Vista de Préstamos por Usuario** - - Lista de usuarios - - Para cada usuario: dispositivos actualmente prestados - - Opcional: historial de préstamos pasados (expandible) - -### Elementos de Interacción - -- Campos de búsqueda en todas las listas -- Botones de acción claros (Prestar, Devolver, Registrar) -- Indicadores visuales de estado (colores, iconos) -- Confirmación de acciones críticas - ---- - -## Notas de Implementación - -Este documento describe los requisitos a nivel de diseño. La implementación específica (lenguaje de programación, base de datos, framework, arquitectura) queda a criterio del equipo de desarrollo y puede variar según las necesidades técnicas. - -Los detalles técnicos como: -- Tecnologías específicas -- Estructura de base de datos física -- APIs -- Autenticación -- Despliegue - -Deberán ser definidos en la fase de diseño técnico y pueden evolucionar sin afectar los requisitos funcionales descritos aquí. diff --git a/TECHNICAL_SPECIFICATIONS.md b/TECHNICAL_SPECIFICATIONS.md deleted file mode 100644 index 8a17aef..0000000 --- a/TECHNICAL_SPECIFICATIONS.md +++ /dev/null @@ -1,149 +0,0 @@ -# Especificaciones Técnicas - -Documento complementario a `REQUIREMENTS.md` con propuestas concretas de implementación técnica. - ---- - -## 1. Concurrencia en Base de Datos - -| Opción | Descripción | Ventajas | Desventajas | -|--------|-------------|---------|-------------| -| **SQLite + WAL** | Modo Write-Ahead Logging | Zero-config, embebido, buena para <100 conexiones | Limitado a 1 escritor simultáneo | -| **PostgreSQL** | Base de datos relacional | Concurrencia completa, transacciones ACID | Requiere servidor | -| **Transacciones** | Aislamiento READ COMMITTED | Previene lecturas sucias | Bloqueos temporales | -| **Locking optimista** | Versión de fila en actualizaciones | Sin bloqueos | Conflictos requieren reintento | - -**Recomendación**: SQLite con WAL para prototipos, PostgreSQL para producción. Usar transacciones para operaciones críticas (préstamo/devolución). - ---- - -## 2. Autenticación Básica - -| Opción | Descripción | Complejidad | -|--------|-------------|-------------| -| **Sesiones (Flask)** | Cookies firmadas | Baja | -| **JWT** | Tokens sin estado | Media | -| **OAuth 2.0** | Delegación a proveedores | Alta | -| **Basic Auth** | HTTP Basic Authentication | Mínima | - -**Flujo mínimo**: -``` -Login (user/pass) → Session/JWT → Middleware verifica rol → Acceso a endpoints -``` - -**Roles sugeridos**: -- `admin`: CRUD completo, gestión de usuarios -- `staff`: Préstamos/devoluciones -- `viewer`: Solo consulta - ---- - -## 3. Separación Frontend/Backend - -| Arquitectura | Descripción | Stack Ejemplo | -|--------------|-------------|---------------| -| **Monolítica + Templates** | Servidor renderiza HTML | Flask+Jinja2, Django | -| **API + SPA** | Backend API, frontend dinámico | FastAPI + React/Vue | -| **API + SSR** | Backend API + renderizado servidor | Next.js + API | -| **Microservicios** | Servicios independientes | Backend API + Frontend estático | - -**Para este proyecto**: -- **Opción A**: Flask + Jinja2 (simple, suficiente para requisitos) -- **Opción B**: FastAPI + React (escalable, separable) - ---- - -## 4. Búsqueda Eficiente (500+ elementos) - -| Opción | Descripción | Implementación | -|--------|-------------|----------------| -| **Índices DB** | B-tree en columnas buscadas | `CREATE INDEX idx_brand ON tablets(brand)` | -| **Búsqueda full-text** | Búsqueda en texto | SQLite FTS5, PostgreSQL tsvector | -| **Filtrado cliente** | JavaScript filtra datos | Ideal para <2000 elementos | -| **Paginación** | Dividir resultados | `LIMIT 50 OFFSET 0` | - -**Recomendación**: Índices en `serial_number`, `brand`, `model`, `user.name`, `user.identification`. - ---- - -## 5. Estructura de Proyecto Propuesta - -``` -project/ -├── backend/ -│ ├── models/ # Entidades (Device, User, Loan) -│ ├── services/ # Lógica de negocio -│ ├── repositories/ # Acceso a datos -│ ├── routes/ # Endpoints/API -│ └── app.py # Configuración -├── frontend/ # Opcional para opción B -│ ├── public/ -│ └── src/ -├── migrations/ # Control de cambios DB -├── tests/ -└── docs/ -``` - ---- - -## 6. Decisiones Clave por Tomar - -| Decisión | Opciones | Impacto | -|----------|----------|---------| -| Base de datos | SQLite / PostgreSQL | Concurrencia, despliegue | -| Autenticación | Sesiones / JWT / Ninguna | Seguridad, complejidad | -| Frontend | Templates / SPA / Ninguno | Experiencia usuario | -| Despliegue | Local / Docker / Cloud | Escalabilidad | - ---- - -## 7. Ejemplo de Implementación Mínima (Pseudocódigo) - -```python -# modelos.py -class Device: - id: int (PK) - serial_number: str (unique) - status: str (available/loaned) - loans: List[Loan] (one-to-many) - -class User: - id: int (PK) - identification: str (unique) - loans: List[Loan] (one-to-many) - -class Loan: - id: int (PK) - device_id: int (FK) - user_id: int (FK) - loan_date: datetime - return_date: datetime (nullable) - status: str (active/returned) - -# servicios/loan_service.py -def loan_device(device_id: int, user_id: int) -> Loan: - with transaction(): # Atomicidad - device = get_device_for_update(device_id) - if device.status != 'available': - raise DeviceNotAvailableError() - - loan = Loan.create( - device_id=device_id, - user_id=user_id, - loan_date=now(), - status='active' - ) - device.status = 'loaned' - return loan -``` - ---- - -## 8. Consideraciones Adicionales - -- **Validaciones**: Únicas (serial_number, identification) a nivel de base de datos -- **Auditoría**: Campos `created_at`, `updated_at` en todas las entidades -- **Backups**: Script para exportar base de datos periódicamente -- **Logging**: Registrar préstamos/devoluciones para auditoría -- **Versionado API**: `/api/v1/...` para compatibilidad futura -- **Pruebas**: Cubrir flujos críticos (préstamo con dispositivo no disponible, devolución de préstamo inexistente) diff --git a/app.py b/app.py index 7dfba4d..a5332b7 100644 --- a/app.py +++ b/app.py @@ -63,22 +63,6 @@ def init_db(): ) ''') - # Create non_loanable_devices table for devices that cannot be loaned - cursor.execute(''' - CREATE TABLE IF NOT EXISTS non_loanable_devices ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - brand TEXT NOT NULL, - model TEXT NOT NULL, - serial_number TEXT UNIQUE NOT NULL, - device_type TEXT NOT NULL, - location TEXT, - status TEXT DEFAULT 'available', - notes TEXT, - purchase_date TEXT, - purchase_cost REAL - ) - ''') - conn.commit() @app.route('/') @@ -335,99 +319,6 @@ def user_loans(): return render_template('user_loans.html', users_with_loans=user_loans_list) -@app.route('/non_loanable_devices') -def non_loanable_devices(): - """Show all non-loanable devices""" - with get_db() as conn: - cursor = conn.cursor() - cursor.execute("SELECT * FROM non_loanable_devices ORDER BY device_type, brand, model") - devices = cursor.fetchall() - - return render_template('non_loanable_devices.html', devices=devices) - - -@app.route('/add_non_loanable_device', methods=['GET', 'POST']) -def add_non_loanable_device(): - """Add a new non-loanable device to inventory""" - if request.method == 'POST': - brand = request.form['brand'] - model = request.form['model'] - serial_number = request.form['serial_number'] - device_type = request.form['device_type'] - location = request.form['location'] - notes = request.form['notes'] - purchase_date = request.form.get('purchase_date', '') - purchase_cost = request.form.get('purchase_cost', '') - - try: - with get_db() as conn: - cursor = conn.cursor() - cursor.execute(''' - INSERT INTO non_loanable_devices - (brand, model, serial_number, device_type, location, status, notes, purchase_date, purchase_cost) - VALUES (?, ?, ?, ?, ?, 'available', ?, ?, ?) - ''', (brand, model, serial_number, device_type, location, notes, purchase_date, purchase_cost)) - conn.commit() - flash('Non-loanable device added successfully!', 'success') - except sqlite3.IntegrityError: - flash('Error: Serial number already exists!', 'error') - - return redirect(url_for('non_loanable_devices')) - - return render_template('add_non_loanable_device.html') - - -@app.route('/edit_non_loanable_device/', methods=['GET', 'POST']) -def edit_non_loanable_device(device_id): - """Edit a non-loanable device""" - with get_db() as conn: - cursor = conn.cursor() - cursor.execute("SELECT * FROM non_loanable_devices WHERE id = ?", (device_id,)) - device = cursor.fetchone() - - if not device: - flash('Error: Device not found!', 'error') - return redirect(url_for('non_loanable_devices')) - - if request.method == 'POST': - brand = request.form['brand'] - model = request.form['model'] - serial_number = request.form['serial_number'] - device_type = request.form['device_type'] - location = request.form['location'] - status = request.form['status'] - notes = request.form['notes'] - purchase_date = request.form.get('purchase_date', '') - purchase_cost = request.form.get('purchase_cost', '') - - try: - cursor.execute(''' - UPDATE non_loanable_devices SET - brand = ?, model = ?, serial_number = ?, device_type = ?, - location = ?, status = ?, notes = ?, purchase_date = ?, purchase_cost = ? - WHERE id = ? - ''', (brand, model, serial_number, device_type, location, status, notes, purchase_date, purchase_cost, device_id)) - conn.commit() - flash('Device updated successfully!', 'success') - return redirect(url_for('non_loanable_devices')) - except sqlite3.IntegrityError: - flash('Error: Serial number already exists!', 'error') - - return render_template('edit_non_loanable_device.html', device=device) - - -@app.route('/delete_non_loanable_device/') -def delete_non_loanable_device(device_id): - """Delete a non-loanable device""" - with get_db() as conn: - cursor = conn.cursor() - cursor.execute("DELETE FROM non_loanable_devices WHERE id = ?", (device_id,)) - conn.commit() - flash('Device deleted successfully!', 'success') - - return redirect(url_for('non_loanable_devices')) - - if __name__ == '__main__': # Initialize database init_db() diff --git a/gestiontablets.sh b/gestiontablets.sh deleted file mode 100644 index 1d4b29d..0000000 --- a/gestiontablets.sh +++ /dev/null @@ -1 +0,0 @@ -vibe --resume fa1bb230 diff --git a/minimal_app.py b/minimal_app.py index 381a26d..ff0295a 100644 --- a/minimal_app.py +++ b/minimal_app.py @@ -44,22 +44,6 @@ def init_db(): ) ''') - # Create non_loanable_devices table - cursor.execute(''' - CREATE TABLE IF NOT EXISTS non_loanable_devices ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - brand TEXT NOT NULL, - model TEXT NOT NULL, - serial_number TEXT UNIQUE NOT NULL, - device_type TEXT NOT NULL, - location TEXT, - status TEXT DEFAULT 'available', - notes TEXT, - purchase_date TEXT, - purchase_cost REAL - ) - ''') - conn.commit() conn.close() @@ -218,59 +202,6 @@ def show_loan_history(): conn.close() - -def add_non_loanable_device(brand, model, serial_number, device_type, location='', notes='', purchase_date='', purchase_cost=None): - """Add a new non-loanable device to inventory""" - conn = sqlite3.connect('tablets.db') - cursor = conn.cursor() - - try: - cursor.execute(''' - INSERT INTO non_loanable_devices - (brand, model, serial_number, device_type, location, status, notes, purchase_date, purchase_cost) - VALUES (?, ?, ?, ?, ?, 'available', ?, ?, ?) - ''', (brand, model, serial_number, device_type, location, notes, purchase_date, purchase_cost)) - conn.commit() - print(f"✓ Added non-loanable device: {brand} {model} ({serial_number}) - Type: {device_type}") - except sqlite3.IntegrityError: - print(f"✗ Error: Serial number {serial_number} already exists") - finally: - conn.close() - - -def show_non_loanable_devices(): - """Show all non-loanable devices""" - conn = sqlite3.connect('tablets.db') - cursor = conn.cursor() - - cursor.execute("SELECT id, brand, model, serial_number, device_type, location, status FROM non_loanable_devices") - devices = cursor.fetchall() - - print("\n=== Non-Loanable Devices ===") - if devices: - for device in devices: - print(f"ID: {device[0]}, Type: {device[4]}, {device[1]} {device[2]} ({device[3]}), Location: {device[5] or 'N/A'}, Status: {device[6]}") - else: - print("No non-loanable devices") - - conn.close() - - -def delete_non_loanable_device(device_id): - """Delete a non-loanable device""" - conn = sqlite3.connect('tablets.db') - cursor = conn.cursor() - - cursor.execute("DELETE FROM non_loanable_devices WHERE id = ?", (device_id,)) - conn.commit() - - if cursor.rowcount > 0: - print(f"✓ Non-loanable device {device_id} deleted") - else: - print(f"✗ Error: Device {device_id} not found") - - conn.close() - def main(): """Main menu""" init_db() @@ -287,12 +218,9 @@ def main(): print("5. Show Available Tablets") print("6. Show Active Loans") print("7. Show Loan History") - print("8. Add Non-Loanable Device") - print("9. Show Non-Loanable Devices") - print("10. Delete Non-Loanable Device") - print("11. Exit") + print("8. Exit") - choice = input("Enter your choice (1-11): ") + choice = input("Enter your choice (1-8): ") if choice == '1': print("\n=== Add Tablet ===") @@ -341,28 +269,6 @@ def main(): show_loan_history() elif choice == '8': - print("\n=== Add Non-Loanable Device ===") - brand = input("Brand: ") - model = input("Model: ") - serial_number = input("Serial Number: ") - device_type = input("Device Type (e.g., projector, monitor): ") - location = input("Location (optional): ") - notes = input("Notes (optional): ") - add_non_loanable_device(brand, model, serial_number, device_type, location, notes) - - elif choice == '9': - show_non_loanable_devices() - - elif choice == '10': - print("\n=== Delete Non-Loanable Device ===") - show_non_loanable_devices() - device_id = input("Enter Device ID to delete: ") - try: - delete_non_loanable_device(int(device_id)) - except ValueError: - print("✗ Error: Invalid ID format") - - elif choice == '11': print("Goodbye!") break diff --git a/simple_app.py b/simple_app.py index 0674035..f50478d 100644 --- a/simple_app.py +++ b/simple_app.py @@ -62,22 +62,6 @@ def init_db(): ) ''') - # Create non_loanable_devices table - cursor.execute(''' - CREATE TABLE IF NOT EXISTS non_loanable_devices ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - brand TEXT NOT NULL, - model TEXT NOT NULL, - serial_number TEXT UNIQUE NOT NULL, - device_type TEXT NOT NULL, - location TEXT, - status TEXT DEFAULT 'available', - notes TEXT, - purchase_date TEXT, - purchase_cost REAL - ) - ''') - conn.commit() class SimpleHTTPRequestHandler(BaseHTTPRequestHandler): diff --git a/templates/add_non_loanable_device.html b/templates/add_non_loanable_device.html deleted file mode 100644 index ae0489e..0000000 --- a/templates/add_non_loanable_device.html +++ /dev/null @@ -1,63 +0,0 @@ -{% extends "base.html" %} - -{% block content %} -

Add Non-Loanable Device

-

Add a device that will be tracked in inventory but cannot be loaned to users (e.g., projectors, monitors, etc.)

- -
-
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - Cancel -
-
-{% endblock %} diff --git a/templates/base.html b/templates/base.html index e93f5f7..629882b 100644 --- a/templates/base.html +++ b/templates/base.html @@ -144,7 +144,6 @@ Loan Tablet Loan History User Loans - Non-Loanable Devices Project Management diff --git a/templates/edit_non_loanable_device.html b/templates/edit_non_loanable_device.html deleted file mode 100644 index 80c90b4..0000000 --- a/templates/edit_non_loanable_device.html +++ /dev/null @@ -1,71 +0,0 @@ -{% extends "base.html" %} - -{% block content %} -

Edit Non-Loanable Device

- -
-
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - Cancel -
-
-{% endblock %} diff --git a/templates/non_loanable_devices.html b/templates/non_loanable_devices.html deleted file mode 100644 index a27e6ac..0000000 --- a/templates/non_loanable_devices.html +++ /dev/null @@ -1,43 +0,0 @@ -{% extends "base.html" %} - -{% block content %} -
-

Non-Loanable Devices Inventory

-

These devices are tracked in inventory but cannot be loaned to users.

- Add Non-Loanable Device - - {% if devices %} - - - - - - - - - - - - - - {% for device in devices %} - - - - - - - - - - {% endfor %} - -
TypeBrandModelSerial NumberLocationStatusActions
{{ device.device_type }}{{ device.brand }}{{ device.model }}{{ device.serial_number }}{{ device.location or '-' }}{{ device.status }} - Edit - Delete -
- {% else %} -

No non-loanable devices registered.

- {% endif %} -
-{% endblock %} diff --git a/templates/user_loans.html b/templates/user_loans.html index 07fac86..8c10045 100644 --- a/templates/user_loans.html +++ b/templates/user_loans.html @@ -7,98 +7,45 @@ This page demonstrates the many-to-many relationship between users and tablets via the loans table.

- -
- - -
- -
+
{% for user_data in users_with_loans %} {% set user = user_data.user %} {% set loans = user_data.loans %} - {% set active_loans = loans|selectattr('status', 'equalto', 'active')|list %} - {% set returned_loans = loans|selectattr('status', 'equalto', 'returned')|list %} -
+

{{ user.name }} ({{ user.identification }})

- - {{ active_loans|length }} active, {{ returned_loans|length }} past - + {{ loans|length }} tablet{{ 's' if loans|length != 1 else '' }} loaned
- {% if active_loans %} -
-

Current Loans

- - - - - - - + {% if loans %} +
TabletSerial NumberLoan DateStatus
+ + + + + + + + + + + {% for loan in loans %} + + + + + + - - - {% for loan in active_loans %} - - - - - - - {% endfor %} - -
TabletSerial NumberLoan DateReturn DateStatus
{{ loan.brand }} {{ loan.model }}{{ loan.serial_number }}{{ loan.loan_date }}{{ loan.return_date or '-' }} + + {{ loan.status }} + +
{{ loan.brand }} {{ loan.model }}{{ loan.serial_number }}{{ loan.loan_date }} - - {{ loan.status }} - -
-
- {% endif %} - - {% if returned_loans %} -
-

- -

- -
- {% endif %} - - {% if not active_loans and not returned_loans %} + {% endfor %} + + + {% else %}

No loans recorded for this user.

{% endif %}
@@ -109,32 +56,6 @@ {% endif %}
- -