feat: Implement warehouse module roles with auto-schema repair and remove module access section

- Add SchemaVerifier class for automatic database schema verification and repair
- Implement warehouse_manager (Level 75) and warehouse_worker (Level 35) roles
- Add zone-based access control for warehouse workers
- Implement worker-manager binding system with zone filtering
- Add comprehensive database auto-repair on Docker initialization
- Remove Module Access section from user form (role-based access only)
- Add autocomplete attributes to password fields for better UX
- Include detailed documentation for warehouse implementation
- Update initialize_db.py with schema verification as Step 0
This commit is contained in:
Quality App Developer
2026-01-28 00:46:59 +02:00
parent e6ff40184a
commit 8de85ca87f
18 changed files with 4194 additions and 167 deletions

View File

@@ -0,0 +1,222 @@
# Warehouse Roles & Zone Binding: Quick Reference
## Role Quick Lookup
| Role | Level | Modules | Input Pages | Reports | Manage Workers | Zone Restricted |
|------|-------|---------|-------------|---------|-----------------|-----------------|
| Super Admin | 100 | All | ✓ | ✓ | ✓ | ✗ |
| Admin | 90 | All | ✓ | ✓ | ✓ | ✗ |
| Manager - Warehouse | 75 | Warehouse | ✓ | ✓ | ✓ | ✗ |
| Manager - Quality | 70 | Quality | ✗ | ✗ | ✗ | N/A |
| Worker - Quality | 50 | Quality | ✗ | ✗ | ✗ | N/A |
| Worker - Warehouse | 35 | Warehouse | ✓ | ✗ | ✗ | ✓ |
---
## Zone Binding Quick Reference
### Create Binding (Python)
```python
from app.modules.settings.warehouse_worker_management import assign_worker_to_manager
# With zone restriction
assign_worker_to_manager(manager_id=6, worker_id=15, warehouse_zone="Cold Storage")
# Without zone (all zones)
assign_worker_to_manager(manager_id=6, worker_id=15, warehouse_zone=None)
```
### Query Zone Filters
```python
from app.access_control import build_zone_filter_sql
# Get SQL filter based on role
filter_sql = build_zone_filter_sql(user_id=15, user_role='warehouse_worker')
# Result: "AND created_by_user_id = 15"
query = f"SELECT * FROM warehouse_entries WHERE status='active' {filter_sql}"
```
### Get Worker's Zone
```python
from app.modules.settings.warehouse_worker_management import get_worker_binding_info
info = get_worker_binding_info(worker_id=15)
# Result: {
# 'manager_id': 6,
# 'manager_name': 'Maria Garcia',
# 'zone': 'Cold Storage',
# 'is_active': 1
# }
```
---
## Access Checks in Routes
### Check Input Access
```python
from app.access_control import can_access_warehouse_input
if not can_access_warehouse_input(session.get('role')):
flash('Access denied', 'error')
return redirect(url_for('main.dashboard'))
```
### Check Report Access
```python
from app.access_control import can_access_warehouse_reports
if not can_access_warehouse_reports(session.get('role')):
flash('Only managers can view reports', 'error')
return redirect(url_for('warehouse.warehouse_index'))
```
### Check Worker Zone
```python
from app.modules.settings.warehouse_worker_management import validate_worker_zone_access
can_access = validate_worker_zone_access(
worker_id=15,
manager_id=6,
zone='Cold Storage'
)
if not can_access:
flash('You cannot input to this zone', 'error')
```
---
## Scenario Examples
### Scenario 1: Manager Creates Entry
```
Maria Garcia (warehouse_manager) at /warehouse/set-boxes-locations
├─ Role check: ✓ can_access_warehouse_input('warehouse_manager')
├─ Zone check: No zone restriction (NULL)
├─ Can select: Any zone in dropdown
└─ Result: Entry created with any zone, visible in her reports
```
### Scenario 2: Worker Creates Entry
```
David Chen (warehouse_worker) at /warehouse/set-boxes-locations
├─ Role check: ✓ can_access_warehouse_input('warehouse_worker')
├─ Zone check: Binding exists (zone='Cold Storage')
├─ Can select: Only 'Cold Storage' in dropdown
├─ Tries to submit zone='High Shelf'
└─ Result: ✗ DENIED - "Cannot input to zone High Shelf"
```
### Scenario 3: Worker Views Reports
```
David Chen (warehouse_worker) tries /warehouse/reports
├─ Role check: ✗ can_access_warehouse_reports('warehouse_worker')
└─ Result: ✗ DENIED - Redirected to warehouse home
```
### Scenario 4: Unassigned Worker
```
Frank Thompson (warehouse_worker, no binding) at /warehouse/
├─ Role: ✓ warehouse_worker
├─ Binding check: ✗ No binding found
└─ Result: ✗ DENIED - "Not assigned to a manager"
```
---
## Database Quick Commands
### See All Worker Bindings
```sql
SELECT m.full_name as Manager, u.full_name as Worker, wmb.warehouse_zone as Zone
FROM worker_manager_bindings wmb
JOIN users m ON wmb.manager_id = m.id
JOIN users u ON wmb.worker_id = u.id
WHERE wmb.is_active = 1
ORDER BY m.full_name, u.full_name;
```
### See All Warehouse Zones
```sql
SELECT DISTINCT warehouse_zone
FROM worker_manager_bindings
WHERE is_active = 1 AND warehouse_zone IS NOT NULL
ORDER BY warehouse_zone;
```
### Get Workers for Manager
```sql
SELECT u.full_name, wmb.warehouse_zone
FROM worker_manager_bindings wmb
JOIN users u ON wmb.worker_id = u.id
WHERE wmb.manager_id = 6 AND wmb.is_active = 1;
```
---
## Common Errors & Solutions
| Error | Cause | Solution |
|-------|-------|----------|
| "Access denied: warehouse input" | User role not warehouse_manager/worker | Assign correct warehouse role |
| "Cannot input to zone X" | Worker zone mismatch | Check binding: `SELECT * FROM worker_manager_bindings WHERE worker_id=?` |
| "Not assigned to a manager" | Worker has no binding | Create binding: `assign_worker_to_manager(...)` |
| "Only managers can view reports" | Worker trying to access /reports | Workers cannot access reports by design |
| Unassigned worker can't see warehouse | No module access checked | Grant 'warehouse' in user_modules table |
---
## Implementation Checklist
### For New Warehouse Route
- [ ] Add access check decorator (`@warehouse_input_required` or `@warehouse_reports_required`)
- [ ] Get user_id and role from session
- [ ] If warehouse_worker, get and validate zone binding
- [ ] Build zone filter SQL for queries
- [ ] Apply filter to all SELECT statements
- [ ] Log zone/role in audit trail
- [ ] Test with manager (should see all workers' data)
- [ ] Test with worker (should see own zone only)
- [ ] Test with unassigned worker (should be denied)
---
## Files to Reference
| File | Purpose |
|------|---------|
| `access_control.py` | Role definitions, permission checks, helper functions |
| `warehouse_worker_management.py` | Worker binding CRUD operations |
| `WAREHOUSE_ROLES_AND_ACCESS_CONTROL.md` | Complete system design |
| `WORKER_MANAGER_BINDING_MODEL.md` | Visual guide and examples |
| `ZONE_FILTERING_IMPLEMENTATION.md` | Implementation guide with code samples |
---
## Key Functions
```python
# Role Checks
can_access_warehouse_input(role) # ✓ Manager & Worker
can_access_warehouse_reports(role) # ✓ Manager only
can_manage_warehouse_workers(role) # ✓ Manager only
# Worker Binding
assign_worker_to_manager(mgr_id, worker_id, zone)
get_manager_workers(manager_id) # List all workers
get_worker_binding_info(worker_id) # Get manager & zone
validate_worker_zone_access(worker_id, mgr_id, zone)
# Zone Filtering
build_zone_filter_sql(user_id, role) # Get SQL WHERE fragment
get_warehouse_zones() # List all zones in use
get_worker_warehouse_zone(worker_id) # Get worker's zone
```
---
**Last Updated**: January 28, 2026
**Version**: 1.0
**Status**: ✅ Ready for Implementation