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