diff --git a/scripts/seed_demo.py b/scripts/seed_demo.py index 86c98baa..75b3c1b2 100644 --- a/scripts/seed_demo.py +++ b/scripts/seed_demo.py @@ -144,6 +144,24 @@ DEMO_STORES = [ "theme_preset": "modern", "custom_domain": "wizamart.shop", }, + { + "merchant_index": 0, # WizaCorp + "store_code": "WIZAGADGETS", + "name": "WizaGadgets", + "subdomain": "wizagadgets", + "description": "Smart home devices and IoT accessories", + "theme_preset": "modern", + "custom_domain": None, + }, + { + "merchant_index": 0, # WizaCorp + "store_code": "WIZAHOME", + "name": "WizaHome", + "subdomain": "wizahome", + "description": "Home appliances and kitchen electronics", + "theme_preset": "classic", + "custom_domain": None, + }, { "merchant_index": 1, # Fashion Group "store_code": "FASHIONHUB", @@ -153,6 +171,15 @@ DEMO_STORES = [ "theme_preset": "vibrant", "custom_domain": "fashionhub.store", }, + { + "merchant_index": 1, # Fashion Group + "store_code": "FASHIONOUTLET", + "name": "Fashion Outlet", + "subdomain": "fashionoutlet", + "description": "Discounted designer fashion and seasonal clearance", + "theme_preset": "vibrant", + "custom_domain": None, + }, { "merchant_index": 2, # BookWorld "store_code": "BOOKSTORE", @@ -162,6 +189,67 @@ DEMO_STORES = [ "theme_preset": "classic", "custom_domain": None, }, + { + "merchant_index": 2, # BookWorld + "store_code": "BOOKDIGITAL", + "name": "BookWorld Digital", + "subdomain": "bookdigital", + "description": "E-books, audiobooks, and digital learning resources", + "theme_preset": "modern", + "custom_domain": None, + }, +] + +# Demo team members (linked to merchants by index, assigned to stores by store_code) +DEMO_TEAM_MEMBERS = [ + # WizaCorp team + { + "merchant_index": 0, + "email": "alice.manager@wizacorp.com", + "password": "password123", + "first_name": "Alice", + "last_name": "Manager", + "store_codes": ["WIZAMART", "WIZAGADGETS"], # manages two stores + "user_type": "member", + }, + { + "merchant_index": 0, + "email": "charlie.staff@wizacorp.com", + "password": "password123", + "first_name": "Charlie", + "last_name": "Staff", + "store_codes": ["WIZAHOME"], + "user_type": "member", + }, + # Fashion Group team + { + "merchant_index": 1, + "email": "diana.stylist@fashiongroup.com", + "password": "password123", + "first_name": "Diana", + "last_name": "Stylist", + "store_codes": ["FASHIONHUB", "FASHIONOUTLET"], + "user_type": "member", + }, + { + "merchant_index": 1, + "email": "eric.sales@fashiongroup.com", + "password": "password123", + "first_name": "Eric", + "last_name": "Sales", + "store_codes": ["FASHIONOUTLET"], + "user_type": "member", + }, + # BookWorld team + { + "merchant_index": 2, + "email": "fiona.editor@bookworld.com", + "password": "password123", + "first_name": "Fiona", + "last_name": "Editor", + "store_codes": ["BOOKSTORE", "BOOKDIGITAL"], + "user_type": "member", + }, ] # Theme presets @@ -458,8 +546,9 @@ def reset_all_data(db: Session): CustomerAddress, Customer, MarketplaceImportJob, + Product, # Product references MarketplaceProduct + MarketplaceProductTranslation, # Translation references MarketplaceProduct MarketplaceProduct, - Product, ContentPage, # Delete store content pages (keep platform defaults) StoreDomain, StoreTheme, @@ -662,6 +751,79 @@ def create_demo_stores( return stores +def create_demo_team_members( + db: Session, stores: list[Store], auth_manager: AuthManager +) -> list[User]: + """Create demo team member users and assign them to stores.""" + + if SEED_MODE == "minimal": + return [] + + team_users = [] + # Build a store_code → Store lookup from the created stores + store_lookup = {s.store_code: s for s in stores} + + for member_data in DEMO_TEAM_MEMBERS: + # Check if user already exists + user = db.execute( + select(User).where(User.email == member_data["email"]) + ).scalar_one_or_none() + + if not user: + user = User( + username=member_data["email"].split("@")[0], + email=member_data["email"], + hashed_password=auth_manager.hash_password(member_data["password"]), + role="store", + first_name=member_data["first_name"], + last_name=member_data["last_name"], + is_active=True, + is_email_verified=True, + created_at=datetime.now(UTC), + updated_at=datetime.now(UTC), + ) + db.add(user) + db.flush() + print_success( + f"Created team member: {user.email} (password: {member_data['password']})" + ) + else: + print_warning(f"Team member already exists: {user.email}") + + team_users.append(user) + + # Assign user to stores + for store_code in member_data["store_codes"]: + store = store_lookup.get(store_code) + if not store: + print_warning(f"Store {store_code} not found, skipping assignment") + continue + + # Check if StoreUser link already exists + existing_link = db.execute( + select(StoreUser).where( + StoreUser.store_id == store.id, + StoreUser.user_id == user.id, + ) + ).scalar_one_or_none() + + if existing_link: + continue + + store_user = StoreUser( + store_id=store.id, + user_id=user.id, + user_type=member_data["user_type"], + is_active=True, + created_at=datetime.now(UTC), + ) + db.add(store_user) + print_success(f" Assigned {user.first_name} to {store.name} as {member_data['user_type']}") + + db.flush() + return team_users + + def create_demo_customers( db: Session, store: Store, auth_manager: AuthManager, count: int ) -> list[Customer]: @@ -905,20 +1067,24 @@ def seed_demo_data(db: Session, auth_manager: AuthManager): print_step(5, "Creating demo stores...") stores = create_demo_stores(db, merchants, auth_manager) - # Step 6: Create customers - print_step(6, "Creating demo customers...") + # Step 6: Create team members + print_step(6, "Creating demo team members...") + create_demo_team_members(db, stores, auth_manager) + + # Step 7: Create customers + print_step(7, "Creating demo customers...") for store in stores: create_demo_customers( db, store, auth_manager, count=settings.seed_customers_per_store ) - # Step 7: Create products - print_step(7, "Creating demo products...") + # Step 8: Create products + print_step(8, "Creating demo products...") for store in stores: create_demo_products(db, store, count=settings.seed_products_per_store) - # Step 8: Create store content pages - print_step(8, "Creating store content page overrides...") + # Step 9: Create store content pages + print_step(9, "Creating store content page overrides...") create_demo_store_content_pages(db, stores) # Commit all changes @@ -935,18 +1101,20 @@ def print_summary(db: Session): merchant_count = db.query(Merchant).count() store_count = db.query(Store).count() user_count = db.query(User).count() + team_member_count = db.query(StoreUser).filter(StoreUser.user_type == "member").count() customer_count = db.query(Customer).count() product_count = db.query(Product).count() platform_pages = db.query(ContentPage).filter(ContentPage.store_id == None).count() store_pages = db.query(ContentPage).filter(ContentPage.store_id != None).count() print("\nšŸ“Š Database Status:") - print(f" Merchants: {merchant_count}") - print(f" Stores: {store_count}") - print(f" Users: {user_count}") - print(f" Customers: {customer_count}") - print(f" Products: {product_count}") - print(f" Content Pages: {platform_pages} platform + {store_pages} store overrides") + print(f" Merchants: {merchant_count}") + print(f" Stores: {store_count}") + print(f" Users: {user_count}") + print(f" Team memberships: {team_member_count}") + print(f" Customers: {customer_count}") + print(f" Products: {product_count}") + print(f" Content Pages: {platform_pages} platform + {store_pages} store overrides") # Show merchant details merchants = db.query(Merchant).all() @@ -959,7 +1127,7 @@ def print_summary(db: Session): if merchant.is_verified: print(" Verified: āœ“") - # Show store details + # Show store details with team members stores = db.query(Store).all() print("\nšŸŖ Demo Stores:") for store in stores: @@ -985,6 +1153,18 @@ def print_summary(db: Session): print(f" Status: {'āœ“ Active' if store.is_active else 'āœ— Inactive'}") + # Show team members for this store + store_users = ( + db.query(StoreUser) + .filter(StoreUser.store_id == store.id) + .all() + ) + if store_users: + for su in store_users: + user = db.query(User).filter(User.id == su.user_id).first() + if user: + print(f" Team: {user.email} ({su.user_type})") + print("\nšŸ” Demo Merchant Owner Credentials:") print("─" * 70) for i, merchant_data in enumerate(DEMO_COMPANIES[:merchant_count], 1): @@ -1002,6 +1182,17 @@ def print_summary(db: Session): ) print() + print("\nšŸ‘„ Demo Team Member Credentials:") + print("─" * 70) + for member_data in DEMO_TEAM_MEMBERS: + merchant_name = DEMO_COMPANIES[member_data["merchant_index"]]["name"] + store_codes = ", ".join(member_data["store_codes"]) + print(f" {member_data['first_name']} {member_data['last_name']} ({merchant_name})") + print(f" Email: {member_data['email']}") + print(f" Password: {member_data['password']}") + print(f" Stores: {store_codes}") + print() + print("\nšŸ›’ Demo Customer Credentials:") print("─" * 70) print(" All customers:")