464 lines
13 KiB
Markdown
464 lines
13 KiB
Markdown
|
|
# CLI vs Web Functionality Comparison
|
||
|
|
|
||
|
|
## Overview
|
||
|
|
|
||
|
|
This document compares the functionality between the **CLI version** (`minimal_app.py`) and the **Web version** (`app.py`) of the Tablet Management System.
|
||
|
|
|
||
|
|
## Current State
|
||
|
|
|
||
|
|
### Web Version (app.py) - Complete Feature Set
|
||
|
|
|
||
|
|
| Feature | Status | Route | Template |
|
||
|
|
|---------|--------|-------|---------|
|
||
|
|
| Add Tablet | ✅ | `/add_tablet` | `add_tablet.html` |
|
||
|
|
| Add User | ✅ | `/add_user` | `add_user.html` |
|
||
|
|
| Loan Tablet | ✅ | `/loan_tablet` | `loan_tablet.html` |
|
||
|
|
| Return Tablet | ✅ | `/return_tablet/<id>` | N/A (redirects) |
|
||
|
|
| Show Available Tablets | ✅ | `/` (index) | `index.html` |
|
||
|
|
| Show Active Loans | ✅ | `/` (index) | `index.html` |
|
||
|
|
| Loan History | ✅ | `/history` | `history.html` |
|
||
|
|
| User Loans | ✅ | `/user_loans` | `user_loans.html` |
|
||
|
|
| Add Non-Loanable Device | ✅ | `/add_non_loanable_device` | `add_non_loanable_device.html` |
|
||
|
|
| Show Non-Loanable Devices | ✅ | `/non_loanable_devices` | `non_loanable_devices.html` |
|
||
|
|
| Edit Non-Loanable Device | ✅ | `/edit_non_loanable_device/<id>` | `edit_non_loanable_device.html` |
|
||
|
|
| Delete Non-Loanable Device | ✅ | `/delete_non_loanable_device/<id>` | N/A (redirects) |
|
||
|
|
| Project Management | ✅ | `/project_management` | `project_management.html` |
|
||
|
|
|
||
|
|
### CLI Version (minimal_app.py) - Incomplete
|
||
|
|
|
||
|
|
| Feature | Status | Function |
|
||
|
|
|---------|--------|----------|
|
||
|
|
| Add Tablet | ✅ | `add_tablet()` |
|
||
|
|
| Add User | ⚠️ Partial | `add_user()` - Missing email/phone |
|
||
|
|
| Loan Tablet | ✅ | `loan_tablet()` |
|
||
|
|
| Return Tablet | ✅ | `return_tablet()` |
|
||
|
|
| Show Available Tablets | ✅ | `show_available_tablets()` |
|
||
|
|
| Show Active Loans | ✅ | `show_active_loans()` |
|
||
|
|
| Loan History | ✅ | `show_loan_history()` |
|
||
|
|
| Add Non-Loanable Device | ✅ | `add_non_loanable_device()` |
|
||
|
|
| Show Non-Loanable Devices | ✅ | `show_non_loanable_devices()` |
|
||
|
|
| Delete Non-Loanable Device | ✅ | `delete_non_loanable_device()` |
|
||
|
|
| Show Users | ✅ | `show_users()` |
|
||
|
|
| **User Loans** | ❌ Missing | N/A |
|
||
|
|
| **Edit Non-Loanable Device** | ❌ Missing | N/A |
|
||
|
|
| **Project Management** | ❌ Missing | N/A |
|
||
|
|
|
||
|
|
## Missing Features in CLI
|
||
|
|
|
||
|
|
### 1. User Management
|
||
|
|
**Web:** Supports name, email, phone, identification
|
||
|
|
**CLI:** Only supports name, identification
|
||
|
|
|
||
|
|
**Missing:**
|
||
|
|
- Email field
|
||
|
|
- Phone field
|
||
|
|
|
||
|
|
### 2. Tablet Management
|
||
|
|
**Web:** Supports brand, model, serial_number, notes
|
||
|
|
**CLI:** Supports brand, model, serial_number
|
||
|
|
|
||
|
|
**Missing:**
|
||
|
|
- Notes field
|
||
|
|
|
||
|
|
### 3. Non-Loanable Devices
|
||
|
|
**Web:** Full CRUD (Create, Read, Update, Delete)
|
||
|
|
**CLI:** Only Create, Read, Delete
|
||
|
|
|
||
|
|
**Missing:**
|
||
|
|
- Edit functionality
|
||
|
|
|
||
|
|
### 4. Additional Features
|
||
|
|
**Web:** Has these features
|
||
|
|
**CLI:** Missing
|
||
|
|
|
||
|
|
- User Loans page (shows loans by user with search)
|
||
|
|
- Project Management (markdown notes editor)
|
||
|
|
- Flash messages (CLI uses print, which is fine)
|
||
|
|
|
||
|
|
## Database Schema Comparison
|
||
|
|
|
||
|
|
### Web Version Schema (app.py)
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- tablets
|
||
|
|
CREATE TABLE tablets (
|
||
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
|
|
brand TEXT NOT NULL,
|
||
|
|
model TEXT NOT NULL,
|
||
|
|
serial_number TEXT UNIQUE NOT NULL,
|
||
|
|
status TEXT DEFAULT 'available',
|
||
|
|
notes TEXT
|
||
|
|
)
|
||
|
|
|
||
|
|
-- users
|
||
|
|
CREATE TABLE users (
|
||
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
|
|
name TEXT NOT NULL,
|
||
|
|
email TEXT,
|
||
|
|
phone TEXT,
|
||
|
|
identification TEXT UNIQUE
|
||
|
|
)
|
||
|
|
|
||
|
|
-- loans
|
||
|
|
CREATE TABLE loans (
|
||
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
|
|
tablet_id INTEGER NOT NULL,
|
||
|
|
user_id INTEGER NOT NULL,
|
||
|
|
loan_date TEXT NOT NULL,
|
||
|
|
return_date TEXT,
|
||
|
|
status TEXT DEFAULT 'active',
|
||
|
|
FOREIGN KEY (tablet_id) REFERENCES tablets (id),
|
||
|
|
FOREIGN KEY (user_id) REFERENCES users (id)
|
||
|
|
)
|
||
|
|
|
||
|
|
-- non_loanable_devices
|
||
|
|
CREATE TABLE 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
|
||
|
|
)
|
||
|
|
```
|
||
|
|
|
||
|
|
### CLI Version Schema (minimal_app.py)
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- tablets
|
||
|
|
CREATE TABLE tablets (
|
||
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
|
|
brand TEXT NOT NULL,
|
||
|
|
model TEXT NOT NULL,
|
||
|
|
serial_number TEXT UNIQUE NOT NULL,
|
||
|
|
status TEXT DEFAULT 'available'
|
||
|
|
-- MISSING: notes TEXT
|
||
|
|
)
|
||
|
|
|
||
|
|
-- users
|
||
|
|
CREATE TABLE users (
|
||
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
|
|
name TEXT NOT NULL,
|
||
|
|
identification TEXT UNIQUE
|
||
|
|
-- MISSING: email TEXT, phone TEXT
|
||
|
|
)
|
||
|
|
|
||
|
|
-- loans
|
||
|
|
CREATE TABLE loans (
|
||
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
|
|
tablet_id INTEGER NOT NULL,
|
||
|
|
user_id INTEGER NOT NULL,
|
||
|
|
loan_date TEXT NOT NULL,
|
||
|
|
return_date TEXT,
|
||
|
|
status TEXT DEFAULT 'active',
|
||
|
|
FOREIGN KEY (tablet_id) REFERENCES tablets (id),
|
||
|
|
FOREIGN KEY (user_id) REFERENCES users (id)
|
||
|
|
)
|
||
|
|
|
||
|
|
-- non_loanable_devices
|
||
|
|
CREATE TABLE 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
|
||
|
|
)
|
||
|
|
```
|
||
|
|
|
||
|
|
**Schema Differences:**
|
||
|
|
- `tablets` table: CLI missing `notes` column
|
||
|
|
- `users` table: CLI missing `email` and `phone` columns
|
||
|
|
|
||
|
|
## Recommendations
|
||
|
|
|
||
|
|
### Option 1: Update CLI to Match Web (Recommended)
|
||
|
|
|
||
|
|
Update `minimal_app.py` to:
|
||
|
|
1. Add `notes` field to tablets
|
||
|
|
2. Add `email` and `phone` fields to users
|
||
|
|
3. Add edit functionality for non-loanable devices
|
||
|
|
4. Add user loans view
|
||
|
|
5. Add project management (optional)
|
||
|
|
|
||
|
|
**Pros:**
|
||
|
|
- CLI has full feature parity with web
|
||
|
|
- Same database schema
|
||
|
|
- Users can use either interface
|
||
|
|
|
||
|
|
**Cons:**
|
||
|
|
- More complex CLI
|
||
|
|
- May not be needed if web is primary interface
|
||
|
|
|
||
|
|
### Option 2: Keep CLI Minimal (Current State)
|
||
|
|
|
||
|
|
Leave CLI as-is for basic operations only.
|
||
|
|
|
||
|
|
**Pros:**
|
||
|
|
- Simple, focused CLI
|
||
|
|
- Less code to maintain
|
||
|
|
|
||
|
|
**Cons:**
|
||
|
|
- Database schema mismatch
|
||
|
|
- Users can't access all features via CLI
|
||
|
|
- Confusing for users who expect same functionality
|
||
|
|
|
||
|
|
### Option 3: Create Separate Database (Not Recommended)
|
||
|
|
|
||
|
|
Use different databases for CLI and web.
|
||
|
|
|
||
|
|
**Pros:**
|
||
|
|
- Each can have optimized schema
|
||
|
|
|
||
|
|
**Cons:**
|
||
|
|
- Data duplication
|
||
|
|
- Sync issues
|
||
|
|
- Confusing for users
|
||
|
|
|
||
|
|
## Suggested Action Plan
|
||
|
|
|
||
|
|
### Priority 1: Fix Database Schema Mismatch
|
||
|
|
|
||
|
|
The CLI's `init_db()` creates tables without `notes`, `email`, and `phone` columns, but the web version expects them. This can cause issues.
|
||
|
|
|
||
|
|
**Solution:** Update `minimal_app.py` `init_db()` to match `app.py` schema.
|
||
|
|
|
||
|
|
### Priority 2: Add Missing Fields to CLI Functions
|
||
|
|
|
||
|
|
1. Update `add_tablet()` to accept and store `notes`
|
||
|
|
2. Update `add_user()` to accept and store `email` and `phone`
|
||
|
|
3. Update `show_available_tablets()` and `show_non_loanable_devices()` to display all fields
|
||
|
|
|
||
|
|
### Priority 3: Add Missing Features (Optional)
|
||
|
|
|
||
|
|
1. Add `edit_non_loanable_device()` function
|
||
|
|
2. Add `show_user_loans()` function
|
||
|
|
3. Consider adding project management (lower priority)
|
||
|
|
|
||
|
|
## Code Changes Required
|
||
|
|
|
||
|
|
### 1. Update init_db() in minimal_app.py
|
||
|
|
|
||
|
|
```python
|
||
|
|
def init_db():
|
||
|
|
"""Initialize database with required tables - MATCH WEB VERSION"""
|
||
|
|
conn = sqlite3.connect('tablets.db')
|
||
|
|
cursor = conn.cursor()
|
||
|
|
|
||
|
|
# Create tablets table - ADD NOTES COLUMN
|
||
|
|
cursor.execute('''
|
||
|
|
CREATE TABLE IF NOT EXISTS tablets (
|
||
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
|
|
brand TEXT NOT NULL,
|
||
|
|
model TEXT NOT NULL,
|
||
|
|
serial_number TEXT UNIQUE NOT NULL,
|
||
|
|
status TEXT DEFAULT 'available',
|
||
|
|
notes TEXT
|
||
|
|
)
|
||
|
|
''')
|
||
|
|
|
||
|
|
# Create users table - ADD EMAIL AND PHONE COLUMNS
|
||
|
|
cursor.execute('''
|
||
|
|
CREATE TABLE IF NOT EXISTS users (
|
||
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
|
|
name TEXT NOT NULL,
|
||
|
|
email TEXT,
|
||
|
|
phone TEXT,
|
||
|
|
identification TEXT UNIQUE
|
||
|
|
)
|
||
|
|
''')
|
||
|
|
|
||
|
|
# loans and non_loanable_devices are already correct
|
||
|
|
# ... rest of init_db
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Update add_tablet() Function
|
||
|
|
|
||
|
|
```python
|
||
|
|
def add_tablet(brand, model, serial_number, notes=''):
|
||
|
|
"""Add a new tablet to inventory"""
|
||
|
|
conn = sqlite3.connect('tablets.db')
|
||
|
|
cursor = conn.cursor()
|
||
|
|
|
||
|
|
try:
|
||
|
|
cursor.execute('''
|
||
|
|
INSERT INTO tablets (brand, model, serial_number, status, notes)
|
||
|
|
VALUES (?, ?, ?, 'available', ?)
|
||
|
|
''', (brand, model, serial_number, notes))
|
||
|
|
conn.commit()
|
||
|
|
print(f"✓ Added tablet: {brand} {model} ({serial_number})")
|
||
|
|
if notes:
|
||
|
|
print(f" Notes: {notes}")
|
||
|
|
except sqlite3.IntegrityError:
|
||
|
|
print(f"✗ Error: Serial number {serial_number} already exists")
|
||
|
|
finally:
|
||
|
|
conn.close()
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. Update add_user() Function
|
||
|
|
|
||
|
|
```python
|
||
|
|
def add_user(name, identification, email='', phone=''):
|
||
|
|
"""Add a new user"""
|
||
|
|
conn = sqlite3.connect('tablets.db')
|
||
|
|
cursor = conn.cursor()
|
||
|
|
|
||
|
|
try:
|
||
|
|
cursor.execute('''
|
||
|
|
INSERT INTO users (name, email, phone, identification)
|
||
|
|
VALUES (?, ?, ?, ?)
|
||
|
|
''', (name, email, phone, identification))
|
||
|
|
conn.commit()
|
||
|
|
print(f"✓ Added user: {name} ({identification})")
|
||
|
|
if email:
|
||
|
|
print(f" Email: {email}")
|
||
|
|
if phone:
|
||
|
|
print(f" Phone: {phone}")
|
||
|
|
except sqlite3.IntegrityError:
|
||
|
|
print(f"✗ Error: Identification {identification} already exists")
|
||
|
|
finally:
|
||
|
|
conn.close()
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4. Update show_available_tablets() to Display Notes
|
||
|
|
|
||
|
|
```python
|
||
|
|
def show_available_tablets():
|
||
|
|
"""Show available tablets"""
|
||
|
|
conn = sqlite3.connect('tablets.db')
|
||
|
|
cursor = conn.cursor()
|
||
|
|
|
||
|
|
cursor.execute("SELECT id, brand, model, serial_number, notes FROM tablets WHERE status = 'available'")
|
||
|
|
tablets = cursor.fetchall()
|
||
|
|
|
||
|
|
print("\n=== Available Tablets ===")
|
||
|
|
if tablets:
|
||
|
|
for tablet in tablets:
|
||
|
|
notes = f" | Notes: {tablet[4]}" if tablet[4] else ""
|
||
|
|
print(f"ID: {tablet[0]}, {tablet[1]} {tablet[2]} ({tablet[3]}){notes}")
|
||
|
|
else:
|
||
|
|
print("No available tablets")
|
||
|
|
|
||
|
|
conn.close()
|
||
|
|
```
|
||
|
|
|
||
|
|
### 5. Add Missing Functions
|
||
|
|
|
||
|
|
#### Edit Non-Loanable Device
|
||
|
|
|
||
|
|
```python
|
||
|
|
def edit_non_loanable_device(device_id, **kwargs):
|
||
|
|
"""Edit a non-loanable device"""
|
||
|
|
conn = sqlite3.connect('tablets.db')
|
||
|
|
cursor = conn.cursor()
|
||
|
|
|
||
|
|
# Build update query dynamically
|
||
|
|
updates = []
|
||
|
|
params = []
|
||
|
|
for key, value in kwargs.items():
|
||
|
|
if value is not None:
|
||
|
|
updates.append(f"{key} = ?")
|
||
|
|
params.append(value)
|
||
|
|
|
||
|
|
if not updates:
|
||
|
|
print("✗ No fields to update")
|
||
|
|
conn.close()
|
||
|
|
return
|
||
|
|
|
||
|
|
params.append(device_id)
|
||
|
|
query = f"UPDATE non_loanable_devices SET {', '.join(updates)} WHERE id = ?"
|
||
|
|
|
||
|
|
cursor.execute(query, params)
|
||
|
|
conn.commit()
|
||
|
|
|
||
|
|
if cursor.rowcount > 0:
|
||
|
|
print(f"✓ Non-loanable device {device_id} updated")
|
||
|
|
else:
|
||
|
|
print(f"✗ Error: Device {device_id} not found")
|
||
|
|
|
||
|
|
conn.close()
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Show User Loans
|
||
|
|
|
||
|
|
```python
|
||
|
|
def show_user_loans():
|
||
|
|
"""Show loans grouped by user"""
|
||
|
|
conn = sqlite3.connect('tablets.db')
|
||
|
|
cursor = conn.cursor()
|
||
|
|
|
||
|
|
# Get all users with their loans
|
||
|
|
cursor.execute('''
|
||
|
|
SELECT u.id, u.name, u.identification,
|
||
|
|
GROUP_CONCAT(l.id, ",") as loan_ids,
|
||
|
|
COUNT(l.id) as loan_count
|
||
|
|
FROM users u
|
||
|
|
LEFT JOIN loans l ON u.id = l.user_id
|
||
|
|
GROUP BY u.id, u.name, u.identification
|
||
|
|
''')
|
||
|
|
users = cursor.fetchall()
|
||
|
|
|
||
|
|
print("\n=== User Loans ===")
|
||
|
|
if users:
|
||
|
|
for user in users:
|
||
|
|
print(f"\nUser: {user[1]} ({user[2]}) - {user[3]} loans")
|
||
|
|
|
||
|
|
# Get loans for this user
|
||
|
|
cursor.execute('''
|
||
|
|
SELECT l.id, t.brand, t.model, t.serial_number, l.loan_date, l.return_date, l.status
|
||
|
|
FROM loans l
|
||
|
|
JOIN tablets t ON l.tablet_id = t.id
|
||
|
|
WHERE l.user_id = ?
|
||
|
|
ORDER BY l.loan_date DESC
|
||
|
|
''', (user[0],))
|
||
|
|
loans = cursor.fetchall()
|
||
|
|
|
||
|
|
for loan in loans:
|
||
|
|
return_date = loan[5] or 'Not returned'
|
||
|
|
print(f" Loan {loan[0]}: {loan[1]} {loan[2]} ({loan[3]})")
|
||
|
|
print(f" Loan Date: {loan[4]}, Return Date: {return_date}, Status: {loan[6]}")
|
||
|
|
else:
|
||
|
|
print("No users found")
|
||
|
|
|
||
|
|
conn.close()
|
||
|
|
```
|
||
|
|
|
||
|
|
## Migration Strategy
|
||
|
|
|
||
|
|
If you want to update the CLI to match the web version:
|
||
|
|
|
||
|
|
1. **Backup current database**
|
||
|
|
```bash
|
||
|
|
cp tablets.db tablets.db.backup
|
||
|
|
```
|
||
|
|
|
||
|
|
2. **Update minimal_app.py** with the changes above
|
||
|
|
|
||
|
|
3. **Run updated CLI**
|
||
|
|
```bash
|
||
|
|
python3 minimal_app.py
|
||
|
|
```
|
||
|
|
|
||
|
|
4. **Test all functionality**
|
||
|
|
|
||
|
|
5. **If database schema changed**, you may need to:
|
||
|
|
- Drop and recreate tables (if starting fresh)
|
||
|
|
- Or add missing columns with ALTER TABLE (if preserving data)
|
||
|
|
|
||
|
|
## Conclusion
|
||
|
|
|
||
|
|
The CLI version is **lagging behind** the web version in terms of:
|
||
|
|
- Database schema (missing columns)
|
||
|
|
- Feature completeness (missing functions)
|
||
|
|
- Field support (missing email, phone, notes)
|
||
|
|
|
||
|
|
**Recommendation:** Update the CLI to match the web version's database schema and functionality to ensure consistency and avoid confusion for users who may use both interfaces.
|