Add factories and seeders for business types, plans, subscriptions, tenants, and users
This commit is contained in:
parent
affe5187fc
commit
ce71aa3ad8
33
app/factories/__init__.py
Normal file
33
app/factories/__init__.py
Normal file
@ -0,0 +1,33 @@
|
||||
import random
|
||||
import string
|
||||
|
||||
|
||||
class Factory:
|
||||
model = None
|
||||
|
||||
def definition(self) -> dict:
|
||||
raise NotImplementedError
|
||||
|
||||
def make(self, **overrides) -> dict:
|
||||
data = self.definition()
|
||||
data.update(overrides)
|
||||
return {k: v for k, v in data.items() if v is not None}
|
||||
|
||||
def create(self, db, **overrides):
|
||||
data = self.make(**overrides)
|
||||
obj = self.model(**data)
|
||||
db.add(obj)
|
||||
db.flush()
|
||||
return obj
|
||||
|
||||
|
||||
def random_string(length: int = 10) -> str:
|
||||
return "".join(random.choices(string.ascii_lowercase, k=length))
|
||||
|
||||
|
||||
def random_email() -> str:
|
||||
return f"{random_string(8)}@example.com"
|
||||
|
||||
|
||||
def random_phone() -> str:
|
||||
return f"08{random.randint(100000000, 999999999)}"
|
||||
15
app/factories/business_type_factory.py
Normal file
15
app/factories/business_type_factory.py
Normal file
@ -0,0 +1,15 @@
|
||||
from app.factories import Factory, random_string
|
||||
from app.models.business_type import BusinessType
|
||||
|
||||
|
||||
class BusinessTypeFactory(Factory):
|
||||
model = BusinessType
|
||||
|
||||
def definition(self) -> dict:
|
||||
return {
|
||||
"id": None,
|
||||
"code": random_string(8),
|
||||
"name": f"Business {random_string(6).title()}",
|
||||
"description": None,
|
||||
"is_active": True,
|
||||
}
|
||||
17
app/factories/plan_factory.py
Normal file
17
app/factories/plan_factory.py
Normal file
@ -0,0 +1,17 @@
|
||||
from app.factories import Factory, random_string
|
||||
from app.models.plan import Plan
|
||||
|
||||
|
||||
class PlanFactory(Factory):
|
||||
model = Plan
|
||||
|
||||
def definition(self) -> dict:
|
||||
return {
|
||||
"id": None,
|
||||
"code": random_string(6),
|
||||
"name": f"Plan {random_string(6).title()}",
|
||||
"description": None,
|
||||
"price": 0,
|
||||
"limits": None,
|
||||
"is_active": True,
|
||||
}
|
||||
19
app/factories/subscription_factory.py
Normal file
19
app/factories/subscription_factory.py
Normal file
@ -0,0 +1,19 @@
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from app.factories import Factory
|
||||
from app.models.subscription import Subscription
|
||||
|
||||
|
||||
class SubscriptionFactory(Factory):
|
||||
model = Subscription
|
||||
|
||||
def definition(self) -> dict:
|
||||
return {
|
||||
"id": None,
|
||||
"tenant_id": None,
|
||||
"plan_id": None,
|
||||
"limits": None,
|
||||
"status": "TRIAL",
|
||||
"started_at": None,
|
||||
"ended_at": None,
|
||||
}
|
||||
19
app/factories/tenant_factory.py
Normal file
19
app/factories/tenant_factory.py
Normal file
@ -0,0 +1,19 @@
|
||||
from app.factories import Factory, random_phone, random_string
|
||||
from app.models.tenant import Tenant
|
||||
|
||||
|
||||
class TenantFactory(Factory):
|
||||
model = Tenant
|
||||
|
||||
def definition(self) -> dict:
|
||||
slug = random_string(10)
|
||||
return {
|
||||
"id": None,
|
||||
"name": f"Tenant {slug.title()}",
|
||||
"slug": slug,
|
||||
"business_type_id": None,
|
||||
"phone": random_phone(),
|
||||
"address": None,
|
||||
"email": None,
|
||||
"status": "ACTIVE",
|
||||
}
|
||||
18
app/factories/user_factory.py
Normal file
18
app/factories/user_factory.py
Normal file
@ -0,0 +1,18 @@
|
||||
from app.factories import Factory, random_email, random_string
|
||||
from app.models.user import User
|
||||
from app.security import hash_password
|
||||
|
||||
|
||||
class UserFactory(Factory):
|
||||
model = User
|
||||
|
||||
def definition(self) -> dict:
|
||||
return {
|
||||
"id": None,
|
||||
"email": random_email(),
|
||||
"username": random_string(12),
|
||||
"password": hash_password("password123"),
|
||||
"email_verified_at": None,
|
||||
"tenant_id": None,
|
||||
"status": "ACTIVE",
|
||||
}
|
||||
15
app/factories/user_profile_factory.py
Normal file
15
app/factories/user_profile_factory.py
Normal file
@ -0,0 +1,15 @@
|
||||
from app.factories import Factory, random_phone, random_string
|
||||
from app.models.user_profile import UserProfile
|
||||
|
||||
|
||||
class UserProfileFactory(Factory):
|
||||
model = UserProfile
|
||||
|
||||
def definition(self) -> dict:
|
||||
return {
|
||||
"id": None,
|
||||
"user_id": None,
|
||||
"full_name": f"{random_string(6).title()} {random_string(8).title()}",
|
||||
"phone": random_phone(),
|
||||
"timezone": "Asia/Jakarta",
|
||||
}
|
||||
3
app/seeders/__init__.py
Normal file
3
app/seeders/__init__.py
Normal file
@ -0,0 +1,3 @@
|
||||
class Seeder:
|
||||
def run(self, db):
|
||||
raise NotImplementedError
|
||||
9
app/seeders/business_type_seeder.py
Normal file
9
app/seeders/business_type_seeder.py
Normal file
@ -0,0 +1,9 @@
|
||||
from app.factories.business_type_factory import BusinessTypeFactory
|
||||
|
||||
|
||||
def seed_business_types(db, count: int = 5):
|
||||
result = []
|
||||
for i in range(count):
|
||||
bt = BusinessTypeFactory().create(db)
|
||||
result.append(bt)
|
||||
return result
|
||||
44
app/seeders/database_seeder.py
Normal file
44
app/seeders/database_seeder.py
Normal file
@ -0,0 +1,44 @@
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.database import SessionLocal
|
||||
from app.seeders.business_type_seeder import seed_business_types
|
||||
from app.seeders.plan_seeder import seed_plans
|
||||
from app.seeders.subscription_seeder import seed_subscriptions
|
||||
from app.seeders.tenant_seeder import seed_tenants
|
||||
from app.seeders.user_seeder import seed_users
|
||||
|
||||
|
||||
def seed_all(db: Session, count: int = 5):
|
||||
business_types = seed_business_types(db, count)
|
||||
plans = seed_plans(db, count)
|
||||
|
||||
bt_ids = [bt.id for bt in business_types]
|
||||
tenants = seed_tenants(db, count, business_type_ids=bt_ids)
|
||||
|
||||
plan_ids = [p.id for p in plans]
|
||||
tenant_ids = [t.id for t in tenants]
|
||||
seed_subscriptions(db, count, tenant_ids=tenant_ids, plan_ids=plan_ids)
|
||||
|
||||
users = seed_users(db, count)
|
||||
|
||||
db.commit()
|
||||
|
||||
return {
|
||||
"business_types": len(business_types),
|
||||
"plans": len(plans),
|
||||
"tenants": len(tenants),
|
||||
"subscriptions": count,
|
||||
"users": len(users),
|
||||
"user_profiles": len(users),
|
||||
}
|
||||
|
||||
|
||||
def seed_database(count: int = 5):
|
||||
db = SessionLocal()
|
||||
try:
|
||||
result = seed_all(db, count)
|
||||
print("Database seeding completed:")
|
||||
for model, total in result.items():
|
||||
print(f" - {model}: {total}")
|
||||
finally:
|
||||
db.close()
|
||||
9
app/seeders/plan_seeder.py
Normal file
9
app/seeders/plan_seeder.py
Normal file
@ -0,0 +1,9 @@
|
||||
from app.factories.plan_factory import PlanFactory
|
||||
|
||||
|
||||
def seed_plans(db, count: int = 5):
|
||||
result = []
|
||||
for i in range(count):
|
||||
plan = PlanFactory().create(db)
|
||||
result.append(plan)
|
||||
return result
|
||||
14
app/seeders/subscription_seeder.py
Normal file
14
app/seeders/subscription_seeder.py
Normal file
@ -0,0 +1,14 @@
|
||||
from app.factories.subscription_factory import SubscriptionFactory
|
||||
|
||||
|
||||
def seed_subscriptions(db, count: int = 5, tenant_ids: list[str] | None = None, plan_ids: list[str] | None = None):
|
||||
result = []
|
||||
for i in range(count):
|
||||
kwargs = {}
|
||||
if tenant_ids:
|
||||
kwargs["tenant_id"] = tenant_ids[i % len(tenant_ids)]
|
||||
if plan_ids:
|
||||
kwargs["plan_id"] = plan_ids[i % len(plan_ids)]
|
||||
sub = SubscriptionFactory().create(db, **kwargs)
|
||||
result.append(sub)
|
||||
return result
|
||||
12
app/seeders/tenant_seeder.py
Normal file
12
app/seeders/tenant_seeder.py
Normal file
@ -0,0 +1,12 @@
|
||||
from app.factories.tenant_factory import TenantFactory
|
||||
|
||||
|
||||
def seed_tenants(db, count: int = 5, business_type_ids: list[str] | None = None):
|
||||
result = []
|
||||
for i in range(count):
|
||||
kwargs = {}
|
||||
if business_type_ids:
|
||||
kwargs["business_type_id"] = business_type_ids[i % len(business_type_ids)]
|
||||
tenant = TenantFactory().create(db, **kwargs)
|
||||
result.append(tenant)
|
||||
return result
|
||||
47
app/seeders/user_seeder.py
Normal file
47
app/seeders/user_seeder.py
Normal file
@ -0,0 +1,47 @@
|
||||
from app.factories.user_factory import UserFactory
|
||||
from app.models.user import User
|
||||
from app.models.user_profile import UserProfile
|
||||
from app.security import hash_password
|
||||
|
||||
|
||||
def seed_users(db, count: int = 5, tenant_ids: list[str] | None = None):
|
||||
result = []
|
||||
for i in range(count):
|
||||
kwargs = {}
|
||||
if tenant_ids:
|
||||
kwargs["tenant_id"] = tenant_ids[i % len(tenant_ids)]
|
||||
user = UserFactory().create(db, **kwargs)
|
||||
profile = UserProfile(
|
||||
user_id=user.id,
|
||||
full_name="User Default",
|
||||
phone="081234567890",
|
||||
timezone="Asia/Jakarta",
|
||||
)
|
||||
db.add(profile)
|
||||
result.append(user)
|
||||
|
||||
admin = db.query(User).filter(
|
||||
(User.email == "project.pangestuyoga@gmail.com") | (User.username == "pangestu")
|
||||
).first()
|
||||
if not admin:
|
||||
admin = User(
|
||||
email="project.pangestuyoga@gmail.com",
|
||||
username="pangestu",
|
||||
password=hash_password("Minimal8@"),
|
||||
status="ACTIVE",
|
||||
)
|
||||
db.add(admin)
|
||||
db.flush()
|
||||
|
||||
admin_profile = UserProfile(
|
||||
user_id=admin.id,
|
||||
full_name="Pangestu Yoga",
|
||||
phone="081234567890",
|
||||
timezone="Asia/Jakarta",
|
||||
)
|
||||
db.add(admin_profile)
|
||||
else:
|
||||
admin.password = hash_password("Minimal8@")
|
||||
result.append(admin)
|
||||
|
||||
return result
|
||||
21
seed.py
Normal file
21
seed.py
Normal file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
|
||||
from app.seeders.database_seeder import seed_database
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Seed the database with sample data")
|
||||
parser.add_argument(
|
||||
"--count", "-c",
|
||||
type=int,
|
||||
default=5,
|
||||
help="Number of records to seed for each model (default: 5)",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
seed_database(args.count)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Reference in New Issue
Block a user