Fix Demo enterprise

This commit is contained in:
Urtzi Alfaro
2025-12-17 13:03:52 +01:00
parent 0bbfa010bf
commit 8bfe4f2dd7
111 changed files with 26200 additions and 2245 deletions

531
FIXES_SUMMARY.md Normal file
View File

@@ -0,0 +1,531 @@
# Enterprise Demo Fixes Summary
**Date:** 2025-12-17
**Issue:** Child tenants not visible in multi-tenant menu & Distribution data not displaying
## Problems Identified
### 1. Child Tenant Visibility Issue ❌
**Root Cause:** Child tenants were being created with the wrong `owner_id`.
**Location:** `services/tenant/app/api/internal_demo.py:620`
**Problem Details:**
- Child tenants were hardcoded to use the professional demo owner ID: `c1a2b3c4-d5e6-47a8-b9c0-d1e2f3a4b5c6`
- This is INCORRECT for enterprise demos
- The enterprise parent tenant uses owner ID: `d2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7`
- Because of the mismatch, when the enterprise parent owner logged in, they could only see the parent tenant
- The child tenants belonged to a different owner and were not visible in the tenant switcher
**Impact:**
- Parent tenant owner could NOT see child tenants in the multi-tenant menu
- Child tenants existed in the database but were inaccessible
- Enterprise demo was non-functional for testing multi-location features
### 2. Distribution Data File Not Found for Child Tenants ❌
**Root Cause:** Distribution service was trying to load non-existent distribution files for child tenants.
**Location:** `services/distribution/app/api/internal_demo.py:148`
**Problem Details:**
- When cloning data for `enterprise_child` tenants, the code tried to load: `shared/demo/fixtures/enterprise/children/C0000000-0000-4000-a000-000000000001/12-distribution.json`
- These files don't exist because **child outlets are delivery destinations, not distribution hubs**
- Distribution is managed centrally by the parent tenant
- This caused the demo session cloning to fail with FileNotFoundError
**Error Message:**
```
FileNotFoundError: Seed data file not found:
/app/shared/demo/fixtures/enterprise/children/C0000000-0000-4000-a000-000000000001/12-distribution.json
```
**Impact:**
- Demo session cloning failed for enterprise demos
- Child tenant creation was incomplete
- Distribution page showed no data
### 3. Shipment Model Field Mismatch ❌
**Root Cause:** Distribution cloning code tried to create Shipment with fields that don't exist in the model.
**Location:** `services/distribution/app/api/internal_demo.py:283`
**Problem Details:**
- Fixture contains `items` field (list of products being shipped)
- Fixture contains `estimated_delivery_time` field
- Shipment model doesn't have these fields
- Model only has: `actual_delivery_time`, `delivery_notes`, etc.
- This caused TypeError when creating Shipment objects
**Error Message:**
```
TypeError: 'items' is an invalid keyword argument for Shipment
```
**Impact:**
- Distribution data cloning failed completely
- No routes or shipments were created
- Distribution page was empty even after successful child tenant creation
## Fixes Applied
### Fix 1: Child Tenant Owner ID Correction ✅
**File Modified:** `services/tenant/app/api/internal_demo.py`
**Changes Made:**
1. **Added parent tenant lookup** (Lines 599-614):
```python
# Get parent tenant to retrieve the correct owner_id
parent_result = await db.execute(select(Tenant).where(Tenant.id == parent_uuid))
parent_tenant = parent_result.scalars().first()
if not parent_tenant:
logger.error("Parent tenant not found", parent_tenant_id=parent_tenant_id)
return {...}
# Use the parent's owner_id for the child tenant (enterprise demo owner)
parent_owner_id = parent_tenant.owner_id
```
2. **Updated child tenant creation** (Line 637):
```python
# Owner ID - MUST match the parent tenant owner (enterprise demo owner)
# This ensures the parent owner can see and access child tenants
owner_id=parent_owner_id
```
3. **Updated TenantMember creation** (Line 711):
```python
# Use the parent's owner_id (already retrieved above)
# This ensures consistency between tenant.owner_id and TenantMember records
child_owner_member = TenantMember(
tenant_id=virtual_uuid,
user_id=parent_owner_id, # Changed from hardcoded UUID
role="owner",
...
)
```
4. **Enhanced logging** (Line 764):
```python
logger.info(
"Child outlet created successfully",
...
owner_id=str(parent_owner_id), # Added for debugging
...
)
```
### Fix 2: Distribution Data Loading for Child Tenants ✅
**File Modified:** `services/distribution/app/api/internal_demo.py`
**Changes Made:**
1. **Added early return for child tenants** (Lines 147-166):
```python
elif demo_account_type == "enterprise_child":
# Child outlets don't have their own distribution data
# Distribution is managed centrally by the parent tenant
# Child locations are delivery destinations, not distribution hubs
logger.info(
"Skipping distribution cloning for child outlet - distribution managed by parent",
base_tenant_id=base_tenant_id,
virtual_tenant_id=virtual_tenant_id,
session_id=session_id
)
duration_ms = int((datetime.now(timezone.utc) - start_time).total_seconds() * 1000)
return {
"service": "distribution",
"status": "completed",
"records_cloned": 0,
"duration_ms": duration_ms,
"details": {
"note": "Child outlets don't manage distribution - handled by parent tenant"
}
}
```
**Rationale:**
- In an enterprise bakery setup, the **central production facility (parent)** manages all distribution
- **Retail outlets (children)** are **receiving locations**, not distribution hubs
- The parent's distribution.json already includes routes and shipments that reference child tenant locations
- Attempting to load child-specific distribution files was architecturally incorrect
### Fix 3: Shipment Field Compatibility ✅
**File Modified:** `services/distribution/app/api/internal_demo.py`
**Changes Made:**
1. **Removed estimated_delivery_time field** (Lines 261-267):
```python
# Note: The Shipment model doesn't have estimated_delivery_time
# Only actual_delivery_time is stored
actual_delivery_time = parse_date_field(
shipment_data.get('actual_delivery_time'),
session_time,
"actual_delivery_time"
)
```
2. **Stored items in delivery_notes** (Lines 273-287):
```python
# Store items in delivery_notes as JSON for demo purposes
# (In production, items would be in the linked purchase order)
import json
items_json = json.dumps(shipment_data.get('items', [])) if shipment_data.get('items') else None
new_shipment = Shipment(
...
total_weight_kg=shipment_data.get('total_weight_kg'),
actual_delivery_time=actual_delivery_time,
# Store items info in delivery_notes for demo display
delivery_notes=f"{shipment_data.get('notes', '')}\nItems: {items_json}" if items_json else shipment_data.get('notes'),
...
)
```
**Rationale:**
- Shipment model represents delivery tracking, not content inventory
- In production systems, shipment items are stored in the linked purchase order
- For demo purposes, we store items as JSON in the `delivery_notes` field
- This allows the demo to show what's being shipped without requiring full PO integration
## How Data Flows in Enterprise Demo
### User & Ownership Structure
```
Enterprise Demo Owner
├── ID: d2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7
├── Email: director@panaderiaartesana.es
├── Role: owner
├── Parent Tenant (Central Production)
│ ├── ID: 80000000-0000-4000-a000-000000000001 (template)
│ ├── Name: "Panadería Artesana España - Central"
│ ├── Type: parent
│ └── Owner: d2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7
└── Child Tenants (Retail Outlets)
├── Madrid - Salamanca
│ ├── ID: A0000000-0000-4000-a000-000000000001 (template)
│ ├── Type: child
│ └── Owner: d2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7 ✅ (NOW CORRECT)
├── Barcelona - Eixample
│ ├── ID: B0000000-0000-4000-a000-000000000001
│ └── Owner: d2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7 ✅
├── Valencia - Ruzafa
│ ├── ID: C0000000-0000-4000-a000-000000000001
│ └── Owner: d2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7 ✅
├── Seville - Triana
│ ├── ID: D0000000-0000-4000-a000-000000000001
│ └── Owner: d2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7 ✅
└── Bilbao - Casco Viejo
├── ID: E0000000-0000-4000-a000-000000000001
└── Owner: d2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7 ✅
```
### Tenant Loading Flow
1. **User logs into enterprise demo**
- Demo session created with `demo_account_type: "enterprise"`
- Session ID stored in JWT token
2. **Frontend requests user tenants**
- Calls: `GET /tenants/user/{user_id}/owned`
- Backend: `services/tenant/app/api/tenant_operations.py:284`
3. **Backend retrieves virtual tenants**
- Extracts `demo_session_id` from JWT
- Calls: `tenant_service.get_virtual_tenants_for_session(demo_session_id, "enterprise")`
- Query: `SELECT * FROM tenants WHERE demo_session_id = ? AND owner_id = ?`
- Returns: Parent + All child tenants with matching owner_id ✅
4. **Frontend displays in TenantSwitcher**
- Component: `frontend/src/components/ui/TenantSwitcher.tsx`
- Shows all tenants where user is owner
- Now includes all 6 tenants (1 parent + 5 children) ✅
### Distribution Data Flow
1. **Demo session cloning**
- Orchestrator calls distribution service: `POST /internal/demo/clone`
- Loads fixture: `shared/demo/fixtures/enterprise/parent/12-distribution.json`
2. **Distribution data includes**
- Delivery routes with route_sequence (stops at multiple locations)
- Shipments linked to child tenants
- All dates use BASE_TS markers for session-relative times
3. **Frontend queries distribution**
- Calls: `GET /tenants/{tenant_id}/distribution/routes?date={date}`
- Calls: `GET /tenants/{tenant_id}/distribution/shipments?date={date}`
- Service: `frontend/src/api/hooks/useEnterpriseDashboard.ts:307`
## Testing Instructions
### 1. Restart Services
After applying the fixes, you need to restart the affected services:
```bash
# Restart tenant service (Fix 1: child tenant owner_id)
kubectl rollout restart deployment tenant-service -n bakery-ia
# Restart distribution service (Fix 2: skip child distribution loading)
kubectl rollout restart deployment distribution-service -n bakery-ia
# Or restart all services at once
./kubernetes_restart.sh
```
### 2. Create New Enterprise Demo Session
**Important:** You must create a NEW demo session to test the fix. Existing sessions have already created child tenants with the wrong owner_id.
```bash
# Navigate to frontend
cd frontend
# Start development server if not running
npm run dev
# Open browser to demo page
# http://localhost:3000/demo
```
### 3. Test Child Tenant Visibility
1. Click "Try Enterprise Demo" button
2. Wait for demo session to initialize
3. After redirect to dashboard, look for the tenant switcher in the top-left
4. Click on the tenant switcher dropdown
5. **Expected Result:** You should see 6 organizations:
- Panadería Artesana España - Central (parent)
- Madrid - Salamanca (child)
- Barcelona - Eixample (child)
- Valencia - Ruzafa (child)
- Seville - Triana (child)
- Bilbao - Casco Viejo (child)
### 4. Test Distribution Page
1. From the enterprise dashboard, navigate to "Distribution"
2. Check if routes and shipments are displayed
3. **Expected Result:** You should see:
- Active routes count
- Pending deliveries count
- Distribution map with route visualization
- List of routes in the "Rutas" tab
### 5. Verify Database (Optional)
If you have database access:
```sql
-- Check child tenant owner_ids
SELECT
id,
name,
tenant_type,
owner_id,
demo_session_id
FROM tenants
WHERE tenant_type = 'child'
AND is_demo = true
ORDER BY created_at DESC
LIMIT 10;
-- Should show owner_id = 'd2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7' for all child tenants
```
## Troubleshooting
### Child Tenants Still Not Visible
1. **Verify you created a NEW demo session** after deploying the fix
- Old sessions have child tenants with wrong owner_id
- Solution: Create a new demo session
2. **Check logs for child tenant creation**
```bash
kubectl logs -f deployment/tenant-service -n bakery-ia | grep "Child outlet created"
```
- Should show: `owner_id=d2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7`
3. **Verify demo session ID in JWT**
- Open browser DevTools > Application > Storage > Local Storage
- Check if `demo_session_id` is present in token
- Should match the session_id in database
### Distribution Data Not Showing
1. **Check date parameter**
- Distribution page defaults to today's date
- Demo data uses BASE_TS (session creation time)
- Routes might be scheduled for BASE_TS + 2h, BASE_TS + 3h, etc.
- Solution: Try querying without date filter or use session date
2. **Verify distribution data was cloned**
```bash
kubectl logs -f deployment/demo-session-service -n bakery-ia | grep "distribution"
```
- Should show: "Distribution data cloning completed"
- Should show: records_cloned > 0
3. **Check backend endpoint**
```bash
# Get tenant ID from tenant switcher
TENANT_ID="your-virtual-tenant-id"
# Query routes directly
curl -H "Authorization: Bearer YOUR_TOKEN" \
"http://localhost:8000/tenants/${TENANT_ID}/distribution/routes"
```
4. **Check browser console for errors**
- Open DevTools > Console
- Look for API errors or failed requests
- Check Network tab for distribution API calls
## Files Changed
1. **services/tenant/app/api/internal_demo.py**
- Lines 599-614: Added parent tenant lookup
- Line 637: Fixed child tenant owner_id
- Line 711: Fixed TenantMember owner_id
- Line 764: Enhanced logging
2. **services/distribution/app/api/internal_demo.py**
- Lines 147-166: Skip distribution cloning for child tenants
- Lines 261-267: Removed unsupported `estimated_delivery_time` field
- Lines 273-292: Fixed `items` field issue (model doesn't support it)
- Stored items data in `delivery_notes` field for demo display
- Added clear logging explaining why child tenants don't get distribution data
## Verification Checklist
- [x] Child tenant owner_id now matches parent tenant owner_id
- [x] Child tenants include demo_session_id for session-based queries
- [x] TenantMember records use consistent owner_id
- [x] Distribution fixture exists with proper structure
- [x] Distribution API endpoints are correctly implemented
- [x] Frontend hooks properly call distribution API
- [x] Distribution cloning skips child tenants (they don't manage distribution)
- [x] FileNotFoundError for child distribution files is resolved
- [x] Shipment model field compatibility issues resolved
- [x] Items data stored in delivery_notes for demo display
## Next Steps
1. **Deploy Fixes**
```bash
kubectl rollout restart deployment tenant-service -n bakery-ia
kubectl rollout restart deployment distribution-service -n bakery-ia
```
2. **Create New Demo Session**
- Must be a new session, old sessions have wrong data
3. **Test Multi-Tenant Menu**
- Verify all 6 tenants visible
- Test switching between tenants
4. **Test Distribution Page**
- Check if data displays
- If not, investigate date filtering
5. **Monitor Logs**
```bash
# Watch tenant service logs
kubectl logs -f deployment/tenant-service -n bakery-ia
# Watch distribution service logs
kubectl logs -f deployment/distribution-service -n bakery-ia
```
## Additional Notes
### Why This Fix Works
The tenant visibility is controlled by the `owner_id` field. When a user logs in and requests their tenants:
1. Backend extracts user_id from JWT: `d2e3f4a5-b6c7-48d9-e0f1-a2b3c4d5e6f7`
2. Queries database: `SELECT * FROM tenants WHERE owner_id = ? AND demo_session_id = ?`
3. Previously: Parent had correct owner_id, children had wrong owner_id → Only parent returned
4. Now: Parent AND children have same owner_id → All tenants returned ✅
### Distribution Data Structure
The distribution fixture creates a realistic enterprise distribution scenario:
- **Routes:** Delivery routes from central production to retail outlets
- **Shipments:** Individual shipments assigned to routes
- **Child References:** Shipments reference child_tenant_id for destination tracking
- **Time Offsets:** Uses BASE_TS + offset for realistic scheduling
Example:
```json
{
"route_number": "MAD-BCN-001",
"route_date": "BASE_TS + 2h", // 2 hours after session creation
"route_sequence": [
{"stop_number": 1, "location_id": "parent-id"},
{"stop_number": 2, "location_id": "child-A-id"},
{"stop_number": 3, "location_id": "child-B-id"}
]
}
```
This creates a distribution network where:
- Central production (parent) produces goods
- Distribution routes deliver to retail outlets (children)
- Shipments track individual deliveries
- All entities are linked for network-wide visibility
---
## Summary of All Changes
### Services Modified
1. **tenant-service** - Fixed child tenant owner_id
2. **distribution-service** - Fixed child cloning + shipment fields
### Database Impact
- Child tenants created in new sessions will have correct owner_id
- Distribution routes and shipments will be created successfully
- No migration needed (only affects new demo sessions)
### Deployment Commands
```bash
# Restart affected services
kubectl rollout restart deployment tenant-service -n bakery-ia
kubectl rollout restart deployment distribution-service -n bakery-ia
# Verify deployments
kubectl rollout status deployment tenant-service -n bakery-ia
kubectl rollout status deployment distribution-service -n bakery-ia
```
### Testing Checklist
- [ ] Create new enterprise demo session
- [ ] Verify 6 tenants visible in tenant switcher
- [ ] Switch between parent and child tenants
- [ ] Navigate to Distribution page on parent tenant
- [ ] Verify routes and shipments are displayed
- [ ] Check demo session logs for errors
---
**Fix Status:** ✅ ALL FIXES COMPLETED
**Testing Status:** ⏳ PENDING USER VERIFICATION
**Production Ready:** ✅ YES (after testing)