New enterprise feature
This commit is contained in:
271
scripts/fix_existing_demo_sessions.py
Executable file
271
scripts/fix_existing_demo_sessions.py
Executable file
@@ -0,0 +1,271 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
One-time data migration script to populate demo_session_id for existing virtual tenants.
|
||||
|
||||
This script fixes existing demo sessions created before the demo_session_id fix was implemented.
|
||||
It links tenants to their sessions using DemoSession.virtual_tenant_id and session_metadata.child_tenant_ids.
|
||||
|
||||
Usage:
|
||||
python3 scripts/fix_existing_demo_sessions.py
|
||||
|
||||
Requirements:
|
||||
- Both demo_session and tenant services must be accessible
|
||||
- Database credentials must be available via environment variables
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import asyncpg
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from typing import List, Dict, Any
|
||||
from uuid import UUID
|
||||
|
||||
# Database connection URLs
|
||||
DEMO_SESSION_DB_URL = os.getenv(
|
||||
"DEMO_SESSION_DATABASE_URL",
|
||||
"postgresql://demo_session_user:demo_password@localhost:5432/demo_session_db"
|
||||
)
|
||||
TENANT_DB_URL = os.getenv(
|
||||
"TENANT_DATABASE_URL",
|
||||
"postgresql://tenant_user:T0uJnXs0r4TUmxSQeQ2DuQGP6HU0LEba@localhost:5432/tenant_db"
|
||||
)
|
||||
|
||||
|
||||
async def get_all_demo_sessions(demo_session_conn) -> List[Dict[str, Any]]:
|
||||
"""Fetch all demo sessions from demo_session database"""
|
||||
query = """
|
||||
SELECT
|
||||
id,
|
||||
session_id,
|
||||
virtual_tenant_id,
|
||||
demo_account_type,
|
||||
session_metadata,
|
||||
status,
|
||||
created_at
|
||||
FROM demo_sessions
|
||||
WHERE status IN ('ready', 'active', 'partial')
|
||||
ORDER BY created_at DESC
|
||||
"""
|
||||
|
||||
rows = await demo_session_conn.fetch(query)
|
||||
sessions = []
|
||||
|
||||
for row in rows:
|
||||
sessions.append({
|
||||
"id": row["id"],
|
||||
"session_id": row["session_id"],
|
||||
"virtual_tenant_id": row["virtual_tenant_id"],
|
||||
"demo_account_type": row["demo_account_type"],
|
||||
"session_metadata": row["session_metadata"],
|
||||
"status": row["status"],
|
||||
"created_at": row["created_at"]
|
||||
})
|
||||
|
||||
return sessions
|
||||
|
||||
|
||||
async def check_tenant_exists(tenant_conn, tenant_id: UUID) -> bool:
|
||||
"""Check if a tenant exists in the tenant database"""
|
||||
query = """
|
||||
SELECT id FROM tenants WHERE id = $1 AND is_demo = true
|
||||
"""
|
||||
|
||||
result = await tenant_conn.fetchrow(query, tenant_id)
|
||||
return result is not None
|
||||
|
||||
|
||||
async def update_tenant_session_id(tenant_conn, tenant_id: UUID, session_id: str):
|
||||
"""Update a tenant's demo_session_id"""
|
||||
query = """
|
||||
UPDATE tenants
|
||||
SET demo_session_id = $2
|
||||
WHERE id = $1 AND is_demo = true
|
||||
"""
|
||||
|
||||
await tenant_conn.execute(query, tenant_id, session_id)
|
||||
|
||||
|
||||
async def get_tenant_session_id(tenant_conn, tenant_id: UUID) -> str:
|
||||
"""Get the current demo_session_id for a tenant"""
|
||||
query = """
|
||||
SELECT demo_session_id FROM tenants WHERE id = $1 AND is_demo = true
|
||||
"""
|
||||
|
||||
result = await tenant_conn.fetchrow(query, tenant_id)
|
||||
return result["demo_session_id"] if result else None
|
||||
|
||||
|
||||
async def migrate_demo_sessions():
|
||||
"""Main migration function"""
|
||||
|
||||
print("=" * 80)
|
||||
print("Demo Session Migration Script")
|
||||
print("=" * 80)
|
||||
print(f"Started at: {datetime.now()}")
|
||||
print()
|
||||
|
||||
# Connect to both databases
|
||||
print("Connecting to databases...")
|
||||
demo_session_conn = await asyncpg.connect(DEMO_SESSION_DB_URL)
|
||||
tenant_conn = await asyncpg.connect(TENANT_DB_URL)
|
||||
print("✓ Connected to both databases")
|
||||
print()
|
||||
|
||||
try:
|
||||
# Fetch all demo sessions
|
||||
print("Fetching demo sessions...")
|
||||
sessions = await get_all_demo_sessions(demo_session_conn)
|
||||
print(f"✓ Found {len(sessions)} demo sessions")
|
||||
print()
|
||||
|
||||
# Statistics
|
||||
stats = {
|
||||
"sessions_processed": 0,
|
||||
"tenants_updated": 0,
|
||||
"tenants_already_set": 0,
|
||||
"tenants_not_found": 0,
|
||||
"errors": 0
|
||||
}
|
||||
|
||||
# Process each session
|
||||
for session in sessions:
|
||||
session_id = session["session_id"]
|
||||
virtual_tenant_id = session["virtual_tenant_id"]
|
||||
demo_account_type = session["demo_account_type"]
|
||||
session_metadata = session["session_metadata"] or {}
|
||||
|
||||
print(f"Processing session: {session_id}")
|
||||
print(f" Type: {demo_account_type}")
|
||||
print(f" Main tenant: {virtual_tenant_id}")
|
||||
|
||||
tenant_ids_to_update = [virtual_tenant_id]
|
||||
|
||||
# For enterprise sessions, also get child tenant IDs
|
||||
if demo_account_type in ["enterprise_chain", "enterprise_parent"]:
|
||||
child_tenant_ids = session_metadata.get("child_tenant_ids", [])
|
||||
if child_tenant_ids:
|
||||
# Convert string UUIDs to UUID objects
|
||||
child_uuids = [UUID(tid) if isinstance(tid, str) else tid for tid in child_tenant_ids]
|
||||
tenant_ids_to_update.extend(child_uuids)
|
||||
print(f" Child tenants: {len(child_uuids)}")
|
||||
|
||||
# Update each tenant
|
||||
session_tenants_updated = 0
|
||||
for tenant_id in tenant_ids_to_update:
|
||||
try:
|
||||
# Check if tenant exists
|
||||
exists = await check_tenant_exists(tenant_conn, tenant_id)
|
||||
if not exists:
|
||||
print(f" ⚠ Tenant {tenant_id} not found - skipping")
|
||||
stats["tenants_not_found"] += 1
|
||||
continue
|
||||
|
||||
# Check current session_id
|
||||
current_session_id = await get_tenant_session_id(tenant_conn, tenant_id)
|
||||
|
||||
if current_session_id == session_id:
|
||||
print(f" ✓ Tenant {tenant_id} already has session_id set")
|
||||
stats["tenants_already_set"] += 1
|
||||
continue
|
||||
|
||||
# Update the tenant
|
||||
await update_tenant_session_id(tenant_conn, tenant_id, session_id)
|
||||
print(f" ✓ Updated tenant {tenant_id}")
|
||||
stats["tenants_updated"] += 1
|
||||
session_tenants_updated += 1
|
||||
|
||||
except Exception as e:
|
||||
print(f" ✗ Error updating tenant {tenant_id}: {e}")
|
||||
stats["errors"] += 1
|
||||
|
||||
stats["sessions_processed"] += 1
|
||||
print(f" Session complete: {session_tenants_updated} tenant(s) updated")
|
||||
print()
|
||||
|
||||
# Print summary
|
||||
print("=" * 80)
|
||||
print("Migration Complete!")
|
||||
print("=" * 80)
|
||||
print(f"Sessions processed: {stats['sessions_processed']}")
|
||||
print(f"Tenants updated: {stats['tenants_updated']}")
|
||||
print(f"Tenants already set: {stats['tenants_already_set']}")
|
||||
print(f"Tenants not found: {stats['tenants_not_found']}")
|
||||
print(f"Errors: {stats['errors']}")
|
||||
print()
|
||||
print(f"Finished at: {datetime.now()}")
|
||||
print("=" * 80)
|
||||
|
||||
# Return success status
|
||||
return stats["errors"] == 0
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ Migration failed with error: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
finally:
|
||||
# Close connections
|
||||
await demo_session_conn.close()
|
||||
await tenant_conn.close()
|
||||
print("Database connections closed")
|
||||
|
||||
|
||||
async def verify_migration():
|
||||
"""Verify that the migration was successful"""
|
||||
|
||||
print()
|
||||
print("=" * 80)
|
||||
print("Verification Check")
|
||||
print("=" * 80)
|
||||
|
||||
tenant_conn = await asyncpg.connect(TENANT_DB_URL)
|
||||
|
||||
try:
|
||||
# Count tenants without session_id
|
||||
query = """
|
||||
SELECT COUNT(*) as count
|
||||
FROM tenants
|
||||
WHERE is_demo = true AND demo_session_id IS NULL
|
||||
"""
|
||||
|
||||
result = await tenant_conn.fetchrow(query)
|
||||
null_count = result["count"]
|
||||
|
||||
if null_count == 0:
|
||||
print("✓ All demo tenants have demo_session_id set")
|
||||
else:
|
||||
print(f"⚠ {null_count} demo tenant(s) still have NULL demo_session_id")
|
||||
print(" These may be template tenants or orphaned records")
|
||||
|
||||
# Count tenants with session_id
|
||||
query2 = """
|
||||
SELECT COUNT(*) as count
|
||||
FROM tenants
|
||||
WHERE is_demo = true AND demo_session_id IS NOT NULL
|
||||
"""
|
||||
|
||||
result2 = await tenant_conn.fetchrow(query2)
|
||||
set_count = result2["count"]
|
||||
print(f"✓ {set_count} demo tenant(s) have demo_session_id set")
|
||||
|
||||
print("=" * 80)
|
||||
print()
|
||||
|
||||
finally:
|
||||
await tenant_conn.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run migration
|
||||
success = asyncio.run(migrate_demo_sessions())
|
||||
|
||||
# Run verification
|
||||
if success:
|
||||
asyncio.run(verify_migration())
|
||||
sys.exit(0)
|
||||
else:
|
||||
print("Migration failed - see errors above")
|
||||
sys.exit(1)
|
||||
@@ -1,179 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Master Demo Data Seeding Script
|
||||
# Seeds all demo data for base template tenants
|
||||
#
|
||||
# This script executes all individual seed scripts in the correct order
|
||||
# to populate the base demo template tenants with complete, realistic data
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/seed_all_demo_data.sh [--skip-existing]
|
||||
#
|
||||
# Options:
|
||||
# --skip-existing Skip seeding if data already exists (idempotent)
|
||||
#
|
||||
# Environment Variables Required:
|
||||
# - DATABASE_URL or service-specific database URLs
|
||||
# - DEMO_MODE=production (recommended for consistent seeding)
|
||||
# - LOG_LEVEL=INFO (default)
|
||||
#
|
||||
|
||||
set -e # Exit on error
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Configuration
|
||||
SKIP_EXISTING=false
|
||||
if [[ "$1" == "--skip-existing" ]]; then
|
||||
SKIP_EXISTING=true
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo -e "${BLUE}Demo Data Seeding - Bakery IA${NC}"
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo ""
|
||||
echo -e "${YELLOW}⚠️ This script will seed demo data for:${NC}"
|
||||
echo -e " - Panadería San Pablo (Individual Bakery)"
|
||||
echo -e " - Panadería La Espiga (Central Workshop)"
|
||||
echo ""
|
||||
echo -e "${YELLOW}Execution Order:${NC}"
|
||||
echo -e " 1. Auth: Users (enhanced with staff roles)"
|
||||
echo -e " 2. Tenant: Tenant members (link staff to tenants)"
|
||||
echo -e " 3. Inventory: Stock batches with expiration dates"
|
||||
echo -e " 4. Orders: Customers"
|
||||
echo -e " 5. Orders: Customer orders"
|
||||
echo -e " 6. Suppliers: Supplier data"
|
||||
echo -e " 7. Procurement: Procurement plans"
|
||||
echo -e " 8. Procurement: Purchase orders"
|
||||
echo -e " 9. Production: Equipment"
|
||||
echo -e " 10. Production: Production schedules"
|
||||
echo -e " 11. Production: Quality check templates"
|
||||
echo -e " 12. Forecasting: Demand forecasts"
|
||||
echo ""
|
||||
|
||||
# Prompt for confirmation
|
||||
read -p "Continue? (y/n) " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo -e "${RED}Aborted.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}Starting demo data seeding...${NC}"
|
||||
echo ""
|
||||
|
||||
# Function to run a seed script
|
||||
run_seed() {
|
||||
local service=$1
|
||||
local script=$2
|
||||
local description=$3
|
||||
|
||||
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||||
echo -e "${GREEN}▶ ${description}${NC}"
|
||||
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━${NC}"
|
||||
|
||||
local script_path="$PROJECT_ROOT/services/$service/scripts/demo/$script"
|
||||
|
||||
if [[ ! -f "$script_path" ]]; then
|
||||
echo -e "${YELLOW}⚠ Script not found: $script_path${NC}"
|
||||
echo -e "${YELLOW} Skipping...${NC}"
|
||||
echo ""
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Export PYTHONPATH
|
||||
export PYTHONPATH="$PROJECT_ROOT:$PROJECT_ROOT/services/$service:$PYTHONPATH"
|
||||
|
||||
# Run the script
|
||||
if python3 "$script_path"; then
|
||||
echo -e "${GREEN}✅ ${description} - Completed${NC}"
|
||||
else
|
||||
echo -e "${RED}❌ ${description} - Failed${NC}"
|
||||
echo -e "${RED} Check logs above for errors${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Phase 1: Users (Enhanced with Staff Roles)
|
||||
# ============================================================================
|
||||
run_seed "auth" "seed_demo_users.py" "Seeding demo users with staff roles"
|
||||
|
||||
# ============================================================================
|
||||
# Phase 2: Tenant Members (Link Staff to Tenants)
|
||||
# ============================================================================
|
||||
run_seed "tenant" "seed_demo_tenant_members.py" "Linking staff users to tenants"
|
||||
|
||||
# ============================================================================
|
||||
# Phase 3: Inventory Stock
|
||||
# ============================================================================
|
||||
run_seed "inventory" "seed_demo_stock.py" "Seeding inventory stock batches"
|
||||
|
||||
# ============================================================================
|
||||
# Phase 4: Customers & Orders
|
||||
# ============================================================================
|
||||
run_seed "orders" "seed_demo_customers.py" "Seeding customer data"
|
||||
run_seed "orders" "seed_demo_orders.py" "Seeding customer orders"
|
||||
|
||||
# ============================================================================
|
||||
# Phase 5: Procurement (New Architecture)
|
||||
# ============================================================================
|
||||
run_seed "procurement" "seed_demo_suppliers.py" "Seeding supplier data"
|
||||
run_seed "procurement" "seed_demo_procurement_plans.py" "Seeding procurement plans"
|
||||
run_seed "procurement" "seed_demo_purchase_orders.py" "Seeding purchase orders"
|
||||
|
||||
# ============================================================================
|
||||
# Phase 6: Production Equipment & Schedules
|
||||
# ============================================================================
|
||||
run_seed "production" "seed_demo_equipment.py" "Seeding production equipment"
|
||||
run_seed "production" "seed_demo_production_schedules.py" "Seeding production schedules"
|
||||
|
||||
# ============================================================================
|
||||
# Phase 7: Quality Templates
|
||||
# ============================================================================
|
||||
run_seed "production" "seed_demo_quality_templates.py" "Seeding quality check templates"
|
||||
|
||||
# ============================================================================
|
||||
# Phase 8: Forecasting
|
||||
# ============================================================================
|
||||
run_seed "forecasting" "seed_demo_forecasts.py" "Seeding demand forecasts"
|
||||
|
||||
# ============================================================================
|
||||
# Phase 9: Orchestration Runs
|
||||
# ============================================================================
|
||||
run_seed "orchestrator" "seed_demo_orchestration_runs.py" "Seeding orchestration runs with reasoning"
|
||||
|
||||
# ============================================================================
|
||||
# Summary
|
||||
# ============================================================================
|
||||
echo ""
|
||||
echo -e "${GREEN}========================================${NC}"
|
||||
echo -e "${GREEN}✅ Demo Data Seeding Completed${NC}"
|
||||
echo -e "${GREEN}========================================${NC}"
|
||||
echo ""
|
||||
echo -e "${YELLOW}Next Steps:${NC}"
|
||||
echo " 1. Verify data in base template tenants:"
|
||||
echo " - San Pablo: a1b2c3d4-e5f6-47a8-b9c0-d1e2f3a4b5c6"
|
||||
echo " - La Espiga: b2c3d4e5-f6a7-48b9-c0d1-e2f3a4b5c6d7"
|
||||
echo ""
|
||||
echo " 2. Test demo session creation:"
|
||||
echo " curl -X POST http://localhost:8000/demo/sessions \\"
|
||||
echo " -H 'Content-Type: application/json' \\"
|
||||
echo " -d '{\"account_type\": \"individual_bakery\"}'"
|
||||
echo ""
|
||||
echo " 3. Verify alert generation works"
|
||||
echo " 4. Check date offset calculations"
|
||||
echo ""
|
||||
echo -e "${GREEN}🎉 Demo environment ready for cloning!${NC}"
|
||||
echo ""
|
||||
297
scripts/validate_demo_seeding.sh
Executable file
297
scripts/validate_demo_seeding.sh
Executable file
@@ -0,0 +1,297 @@
|
||||
#!/bin/bash
|
||||
# validate_demo_seeding.sh
|
||||
# Comprehensive smoke test for demo seeding validation
|
||||
# Tests both Professional and Enterprise demo templates
|
||||
|
||||
set -e # Exit on error
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Counters
|
||||
TESTS_PASSED=0
|
||||
TESTS_FAILED=0
|
||||
TESTS_TOTAL=0
|
||||
|
||||
# Fixed Demo Tenant IDs
|
||||
DEMO_TENANT_PROFESSIONAL="a1b2c3d4-e5f6-47a8-b9c0-d1e2f3a4b5c6"
|
||||
DEMO_TENANT_ENTERPRISE_PARENT="c3d4e5f6-a7b8-49c0-d1e2-f3a4b5c6d7e8"
|
||||
DEMO_TENANT_CHILD_1="d4e5f6a7-b8c9-40d1-e2f3-a4b5c6d7e8f9"
|
||||
DEMO_TENANT_CHILD_2="e5f6a7b8-c9d0-41e2-f3a4-b5c6d7e8f9a0"
|
||||
DEMO_TENANT_CHILD_3="f6a7b8c9-d0e1-42f3-a4b5-c6d7e8f9a0b1"
|
||||
|
||||
# Database connection strings (from Kubernetes secrets)
|
||||
get_db_url() {
|
||||
local service=$1
|
||||
kubectl get secret database-secrets -n bakery-ia -o jsonpath="{.data.${service}_DATABASE_URL}" | base64 -d
|
||||
}
|
||||
|
||||
# Test helper functions
|
||||
test_start() {
|
||||
TESTS_TOTAL=$((TESTS_TOTAL + 1))
|
||||
echo -e "${BLUE}[TEST $TESTS_TOTAL]${NC} $1"
|
||||
}
|
||||
|
||||
test_pass() {
|
||||
TESTS_PASSED=$((TESTS_PASSED + 1))
|
||||
echo -e " ${GREEN}✓ PASS${NC}: $1"
|
||||
}
|
||||
|
||||
test_fail() {
|
||||
TESTS_FAILED=$((TESTS_FAILED + 1))
|
||||
echo -e " ${RED}✗ FAIL${NC}: $1"
|
||||
}
|
||||
|
||||
test_warn() {
|
||||
echo -e " ${YELLOW}⚠ WARN${NC}: $1"
|
||||
}
|
||||
|
||||
# SQL query helper
|
||||
query_db() {
|
||||
local db_url=$1
|
||||
local query=$2
|
||||
kubectl run psql-temp-$RANDOM --rm -i --restart=Never --image=postgres:17-alpine -- \
|
||||
psql "$db_url" -t -c "$query" 2>/dev/null | xargs
|
||||
}
|
||||
|
||||
echo "========================================"
|
||||
echo "🧪 Demo Seeding Validation Test Suite"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
echo "Testing Professional and Enterprise demo templates..."
|
||||
echo ""
|
||||
|
||||
# =============================================================================
|
||||
# PHASE 1: PROFESSIONAL TIER VALIDATION
|
||||
# =============================================================================
|
||||
echo "========================================"
|
||||
echo "📦 Phase 1: Professional Tier (Single Bakery)"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
# Test 1: Tenant Service - Professional tenant exists
|
||||
test_start "Professional tenant exists in tenant service"
|
||||
TENANT_DB=$(get_db_url "TENANT")
|
||||
TENANT_COUNT=$(query_db "$TENANT_DB" "SELECT COUNT(*) FROM tenants WHERE id='$DEMO_TENANT_PROFESSIONAL' AND business_model='individual_bakery'")
|
||||
if [ "$TENANT_COUNT" -eq 1 ]; then
|
||||
test_pass "Professional tenant found (Panadería Artesana Madrid)"
|
||||
else
|
||||
test_fail "Professional tenant not found or incorrect count: $TENANT_COUNT"
|
||||
fi
|
||||
|
||||
# Test 2: Inventory - Professional has raw ingredients
|
||||
test_start "Professional tenant has raw ingredients"
|
||||
INVENTORY_DB=$(get_db_url "INVENTORY")
|
||||
INGREDIENT_COUNT=$(query_db "$INVENTORY_DB" "SELECT COUNT(*) FROM ingredients WHERE tenant_id='$DEMO_TENANT_PROFESSIONAL' AND product_type='INGREDIENT'")
|
||||
if [ "$INGREDIENT_COUNT" -ge 20 ]; then
|
||||
test_pass "Found $INGREDIENT_COUNT raw ingredients (expected ~24)"
|
||||
else
|
||||
test_fail "Insufficient raw ingredients: $INGREDIENT_COUNT (expected >=20)"
|
||||
fi
|
||||
|
||||
# Test 3: Inventory - Professional has finished products
|
||||
test_start "Professional tenant has finished products"
|
||||
PRODUCT_COUNT=$(query_db "$INVENTORY_DB" "SELECT COUNT(*) FROM ingredients WHERE tenant_id='$DEMO_TENANT_PROFESSIONAL' AND product_type='FINISHED_PRODUCT'")
|
||||
if [ "$PRODUCT_COUNT" -ge 4 ]; then
|
||||
test_pass "Found $PRODUCT_COUNT finished products (expected ~4)"
|
||||
else
|
||||
test_fail "Insufficient finished products: $PRODUCT_COUNT (expected >=4)"
|
||||
fi
|
||||
|
||||
# Test 4: Recipes - Professional has recipes
|
||||
test_start "Professional tenant has recipes"
|
||||
RECIPES_DB=$(get_db_url "RECIPES")
|
||||
RECIPE_COUNT=$(query_db "$RECIPES_DB" "SELECT COUNT(*) FROM recipes WHERE tenant_id='$DEMO_TENANT_PROFESSIONAL'")
|
||||
if [ "$RECIPE_COUNT" -ge 4 ]; then
|
||||
test_pass "Found $RECIPE_COUNT recipes (expected ~4-20)"
|
||||
else
|
||||
test_fail "Insufficient recipes: $RECIPE_COUNT (expected >=4)"
|
||||
fi
|
||||
|
||||
# Test 5: Sales - Professional has sales history
|
||||
test_start "Professional tenant has sales history"
|
||||
SALES_DB=$(get_db_url "SALES")
|
||||
SALES_COUNT=$(query_db "$SALES_DB" "SELECT COUNT(*) FROM sales_data WHERE tenant_id='$DEMO_TENANT_PROFESSIONAL'")
|
||||
if [ "$SALES_COUNT" -ge 100 ]; then
|
||||
test_pass "Found $SALES_COUNT sales records (expected ~360 for 90 days)"
|
||||
else
|
||||
test_warn "Lower than expected sales records: $SALES_COUNT (expected >=100)"
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# PHASE 2: ENTERPRISE PARENT VALIDATION
|
||||
# =============================================================================
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo "🏭 Phase 2: Enterprise Parent (Obrador)"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
# Test 6: Tenant Service - Enterprise parent exists
|
||||
test_start "Enterprise parent tenant exists"
|
||||
PARENT_COUNT=$(query_db "$TENANT_DB" "SELECT COUNT(*) FROM tenants WHERE id='$DEMO_TENANT_ENTERPRISE_PARENT' AND business_model='enterprise_chain'")
|
||||
if [ "$PARENT_COUNT" -eq 1 ]; then
|
||||
test_pass "Enterprise parent found (Obrador Madrid)"
|
||||
else
|
||||
test_fail "Enterprise parent not found or incorrect count: $PARENT_COUNT"
|
||||
fi
|
||||
|
||||
# Test 7: Inventory - Parent has raw ingredients (scaled 10x)
|
||||
test_start "Enterprise parent has raw ingredients"
|
||||
PARENT_INGREDIENT_COUNT=$(query_db "$INVENTORY_DB" "SELECT COUNT(*) FROM ingredients WHERE tenant_id='$DEMO_TENANT_ENTERPRISE_PARENT' AND product_type='INGREDIENT'")
|
||||
if [ "$PARENT_INGREDIENT_COUNT" -ge 20 ]; then
|
||||
test_pass "Found $PARENT_INGREDIENT_COUNT raw ingredients (expected ~24)"
|
||||
else
|
||||
test_fail "Insufficient parent raw ingredients: $PARENT_INGREDIENT_COUNT (expected >=20)"
|
||||
fi
|
||||
|
||||
# Test 8: Recipes - Parent has recipes
|
||||
test_start "Enterprise parent has recipes"
|
||||
PARENT_RECIPE_COUNT=$(query_db "$RECIPES_DB" "SELECT COUNT(*) FROM recipes WHERE tenant_id='$DEMO_TENANT_ENTERPRISE_PARENT'")
|
||||
if [ "$PARENT_RECIPE_COUNT" -ge 4 ]; then
|
||||
test_pass "Found $PARENT_RECIPE_COUNT recipes (expected ~4-20)"
|
||||
else
|
||||
test_fail "Insufficient parent recipes: $PARENT_RECIPE_COUNT (expected >=4)"
|
||||
fi
|
||||
|
||||
# Test 9: Production - Parent has production batches
|
||||
test_start "Enterprise parent has production batches"
|
||||
PRODUCTION_DB=$(get_db_url "PRODUCTION")
|
||||
BATCH_COUNT=$(query_db "$PRODUCTION_DB" "SELECT COUNT(*) FROM production_batches WHERE tenant_id='$DEMO_TENANT_ENTERPRISE_PARENT'")
|
||||
if [ "$BATCH_COUNT" -ge 50 ]; then
|
||||
test_pass "Found $BATCH_COUNT production batches (expected ~120)"
|
||||
elif [ "$BATCH_COUNT" -ge 20 ]; then
|
||||
test_warn "Lower production batches: $BATCH_COUNT (expected ~120)"
|
||||
else
|
||||
test_fail "Insufficient production batches: $BATCH_COUNT (expected >=50)"
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# PHASE 3: CHILD RETAIL OUTLETS VALIDATION
|
||||
# =============================================================================
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo "🏪 Phase 3: Child Retail Outlets"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
# Test each child tenant
|
||||
for CHILD_ID in "$DEMO_TENANT_CHILD_1" "$DEMO_TENANT_CHILD_2" "$DEMO_TENANT_CHILD_3"; do
|
||||
case "$CHILD_ID" in
|
||||
"$DEMO_TENANT_CHILD_1") CHILD_NAME="Madrid Centro" ;;
|
||||
"$DEMO_TENANT_CHILD_2") CHILD_NAME="Barcelona Gràcia" ;;
|
||||
"$DEMO_TENANT_CHILD_3") CHILD_NAME="Valencia Ruzafa" ;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
echo "Testing: $CHILD_NAME"
|
||||
echo "----------------------------------------"
|
||||
|
||||
# Test 10a: Child has finished products ONLY (no raw ingredients)
|
||||
test_start "[$CHILD_NAME] Has finished products ONLY"
|
||||
CHILD_PRODUCTS=$(query_db "$INVENTORY_DB" "SELECT COUNT(*) FROM ingredients WHERE tenant_id='$CHILD_ID' AND product_type='FINISHED_PRODUCT'")
|
||||
CHILD_RAW=$(query_db "$INVENTORY_DB" "SELECT COUNT(*) FROM ingredients WHERE tenant_id='$CHILD_ID' AND product_type='INGREDIENT'")
|
||||
|
||||
if [ "$CHILD_PRODUCTS" -eq 4 ] && [ "$CHILD_RAW" -eq 0 ]; then
|
||||
test_pass "Found $CHILD_PRODUCTS finished products, 0 raw ingredients (correct retail model)"
|
||||
elif [ "$CHILD_RAW" -gt 0 ]; then
|
||||
test_fail "Child has raw ingredients ($CHILD_RAW) - should only have finished products"
|
||||
else
|
||||
test_warn "Product count mismatch: $CHILD_PRODUCTS (expected 4)"
|
||||
fi
|
||||
|
||||
# Test 10b: Child has stock batches
|
||||
test_start "[$CHILD_NAME] Has stock batches"
|
||||
CHILD_STOCK=$(query_db "$INVENTORY_DB" "SELECT COUNT(*) FROM stock WHERE tenant_id='$CHILD_ID'")
|
||||
if [ "$CHILD_STOCK" -ge 10 ]; then
|
||||
test_pass "Found $CHILD_STOCK stock batches (expected ~16)"
|
||||
else
|
||||
test_warn "Lower stock batches: $CHILD_STOCK (expected ~16)"
|
||||
fi
|
||||
|
||||
# Test 10c: Child has sales history
|
||||
test_start "[$CHILD_NAME] Has sales history"
|
||||
CHILD_SALES=$(query_db "$SALES_DB" "SELECT COUNT(*) FROM sales_data WHERE tenant_id='$CHILD_ID'")
|
||||
if [ "$CHILD_SALES" -ge 80 ]; then
|
||||
test_pass "Found $CHILD_SALES sales records (expected ~120 for 30 days)"
|
||||
else
|
||||
test_warn "Lower sales records: $CHILD_SALES (expected ~120)"
|
||||
fi
|
||||
|
||||
# Test 10d: Child has customers
|
||||
test_start "[$CHILD_NAME] Has walk-in customers"
|
||||
ORDERS_DB=$(get_db_url "ORDERS")
|
||||
CHILD_CUSTOMERS=$(query_db "$ORDERS_DB" "SELECT COUNT(*) FROM customers WHERE tenant_id='$CHILD_ID'")
|
||||
if [ "$CHILD_CUSTOMERS" -ge 40 ]; then
|
||||
test_pass "Found $CHILD_CUSTOMERS customers (expected 60-100)"
|
||||
else
|
||||
test_warn "Lower customer count: $CHILD_CUSTOMERS (expected 60-100)"
|
||||
fi
|
||||
done
|
||||
|
||||
# =============================================================================
|
||||
# PHASE 4: DISTRIBUTION VALIDATION
|
||||
# =============================================================================
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo "🚚 Phase 4: Distribution & Logistics"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
# Test 11: Distribution routes exist
|
||||
test_start "Distribution routes created (Mon/Wed/Fri pattern)"
|
||||
DISTRIBUTION_DB=$(get_db_url "DISTRIBUTION")
|
||||
ROUTE_COUNT=$(query_db "$DISTRIBUTION_DB" "SELECT COUNT(*) FROM delivery_routes WHERE tenant_id='$DEMO_TENANT_ENTERPRISE_PARENT'")
|
||||
if [ "$ROUTE_COUNT" -ge 10 ]; then
|
||||
test_pass "Found $ROUTE_COUNT delivery routes (expected ~13 for 30 days, Mon/Wed/Fri)"
|
||||
else
|
||||
test_warn "Lower route count: $ROUTE_COUNT (expected ~13)"
|
||||
fi
|
||||
|
||||
# Test 12: Shipments exist for all children
|
||||
test_start "Shipments created for all retail outlets"
|
||||
SHIPMENT_COUNT=$(query_db "$DISTRIBUTION_DB" "SELECT COUNT(*) FROM shipments WHERE parent_tenant_id='$DEMO_TENANT_ENTERPRISE_PARENT'")
|
||||
if [ "$SHIPMENT_COUNT" -ge 30 ]; then
|
||||
test_pass "Found $SHIPMENT_COUNT shipments (expected ~39: 13 routes × 3 children)"
|
||||
else
|
||||
test_warn "Lower shipment count: $SHIPMENT_COUNT (expected ~39)"
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# SUMMARY
|
||||
# =============================================================================
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo "📊 Test Summary"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
echo "Total Tests: $TESTS_TOTAL"
|
||||
echo -e "${GREEN}Passed: $TESTS_PASSED${NC}"
|
||||
echo -e "${RED}Failed: $TESTS_FAILED${NC}"
|
||||
echo ""
|
||||
|
||||
if [ $TESTS_FAILED -eq 0 ]; then
|
||||
echo -e "${GREEN}✅ ALL TESTS PASSED!${NC}"
|
||||
echo ""
|
||||
echo "Demo templates are ready for cloning:"
|
||||
echo " ✓ Professional tier (single bakery): ~3,500 records"
|
||||
echo " ✓ Enterprise parent (Obrador): ~3,000 records"
|
||||
echo " ✓ 3 Child retail outlets: ~700 records"
|
||||
echo " ✓ Distribution history: ~52 records"
|
||||
echo " ✓ Total template data: ~4,200-4,800 records"
|
||||
echo ""
|
||||
exit 0
|
||||
else
|
||||
echo -e "${RED}❌ SOME TESTS FAILED${NC}"
|
||||
echo ""
|
||||
echo "Please review the failed tests above and:"
|
||||
echo " 1. Check that all seed jobs completed successfully"
|
||||
echo " 2. Verify database connections"
|
||||
echo " 3. Check seed script logs for errors"
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user