feat(seed): add multiple stores per merchant and team member seeding

Add 4 new stores (WizaGadgets, WizaHome, Fashion Outlet, BookWorld
Digital) and 5 team member users with store assignments. Fix FK
ordering in reset_all_data to delete Products before MarketplaceProducts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-07 22:39:48 +01:00
parent cea8ac56f8
commit d9ccf0018f

View File

@@ -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:")