Add factories and seeders for business types, plans, subscriptions, tenants, and users

This commit is contained in:
Yoga Pangestu 2026-07-17 23:15:05 +07:00
parent affe5187fc
commit ce71aa3ad8
15 changed files with 295 additions and 0 deletions

33
app/factories/__init__.py Normal file
View 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)}"

View 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,
}

View 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,
}

View 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,
}

View 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",
}

View 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",
}

View 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
View File

@ -0,0 +1,3 @@
class Seeder:
def run(self, db):
raise NotImplementedError

View 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

View 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()

View 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

View 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

View 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

View 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
View 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()