Add models and schemas for users, tenants, subscriptions, plans, and business types
This commit is contained in:
parent
e805f86563
commit
8553971981
15
app/models/__init__.py
Normal file
15
app/models/__init__.py
Normal file
@ -0,0 +1,15 @@
|
||||
from app.models.user import User
|
||||
from app.models.user_profile import UserProfile
|
||||
from app.models.business_type import BusinessType
|
||||
from app.models.plan import Plan
|
||||
from app.models.tenant import Tenant
|
||||
from app.models.subscription import Subscription
|
||||
|
||||
__all__ = [
|
||||
"User",
|
||||
"UserProfile",
|
||||
"BusinessType",
|
||||
"Plan",
|
||||
"Tenant",
|
||||
"Subscription",
|
||||
]
|
||||
21
app/models/business_type.py
Normal file
21
app/models/business_type.py
Normal file
@ -0,0 +1,21 @@
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import Boolean, DateTime, String, Text
|
||||
from sqlalchemy.dialects.mysql import CHAR
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.database import Base
|
||||
|
||||
|
||||
class BusinessType(Base):
|
||||
__tablename__ = "business_types"
|
||||
|
||||
id: Mapped[str] = mapped_column(CHAR(36), primary_key=True, default=lambda: str(uuid.uuid4()))
|
||||
code: Mapped[str] = mapped_column(String(30), unique=True)
|
||||
name: Mapped[str] = mapped_column(String(100))
|
||||
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)
|
||||
updated_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, onupdate=datetime.now)
|
||||
deleted_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||
23
app/models/plan.py
Normal file
23
app/models/plan.py
Normal file
@ -0,0 +1,23 @@
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import Boolean, DateTime, Integer, String, Text
|
||||
from sqlalchemy.dialects.mysql import CHAR, JSON
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.database import Base
|
||||
|
||||
|
||||
class Plan(Base):
|
||||
__tablename__ = "plans"
|
||||
|
||||
id: Mapped[str] = mapped_column(CHAR(36), primary_key=True, default=lambda: str(uuid.uuid4()))
|
||||
code: Mapped[str] = mapped_column(String(20), unique=True)
|
||||
name: Mapped[str] = mapped_column(String(100))
|
||||
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
price: Mapped[int] = mapped_column(Integer)
|
||||
limits: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)
|
||||
updated_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, onupdate=datetime.now)
|
||||
deleted_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||
25
app/models/subscription.py
Normal file
25
app/models/subscription.py
Normal file
@ -0,0 +1,25 @@
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, ForeignKey, String
|
||||
from sqlalchemy.dialects.mysql import CHAR, JSON
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from app.database import Base
|
||||
|
||||
|
||||
class Subscription(Base):
|
||||
__tablename__ = "subscriptions"
|
||||
|
||||
id: Mapped[str] = mapped_column(CHAR(36), primary_key=True, default=lambda: str(uuid.uuid4()))
|
||||
tenant_id: Mapped[str] = mapped_column(CHAR(36), ForeignKey("tenants.id"), unique=True)
|
||||
plan_id: Mapped[str] = mapped_column(CHAR(36), ForeignKey("plans.id"))
|
||||
limits: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
||||
status: Mapped[str] = mapped_column(String(20), default="TRIAL")
|
||||
started_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)
|
||||
ended_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)
|
||||
updated_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, onupdate=datetime.now)
|
||||
|
||||
tenant: Mapped["Tenant"] = relationship(back_populates="subscription")
|
||||
plan: Mapped["Plan"] = relationship()
|
||||
27
app/models/tenant.py
Normal file
27
app/models/tenant.py
Normal file
@ -0,0 +1,27 @@
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, ForeignKey, String, Text
|
||||
from sqlalchemy.dialects.mysql import CHAR
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from app.database import Base
|
||||
|
||||
|
||||
class Tenant(Base):
|
||||
__tablename__ = "tenants"
|
||||
|
||||
id: Mapped[str] = mapped_column(CHAR(36), primary_key=True, default=lambda: str(uuid.uuid4()))
|
||||
name: Mapped[str] = mapped_column(String(200))
|
||||
slug: Mapped[str] = mapped_column(String(100), unique=True)
|
||||
business_type_id: Mapped[str] = mapped_column(CHAR(36), ForeignKey("business_types.id"))
|
||||
phone: Mapped[str | None] = mapped_column(String(20), nullable=True)
|
||||
address: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
email: Mapped[str | None] = mapped_column(String(100), nullable=True)
|
||||
status: Mapped[str] = mapped_column(String(20), default="ACTIVE")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)
|
||||
updated_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, onupdate=datetime.now)
|
||||
deleted_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||
|
||||
business_type: Mapped["BusinessType"] = relationship()
|
||||
subscription: Mapped["Subscription"] = relationship(back_populates="tenant", uselist=False)
|
||||
25
app/models/user.py
Normal file
25
app/models/user.py
Normal file
@ -0,0 +1,25 @@
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, String
|
||||
from sqlalchemy.dialects.mysql import CHAR
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from app.database import Base
|
||||
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = "users"
|
||||
|
||||
id: Mapped[str] = mapped_column(CHAR(36), primary_key=True, default=lambda: str(uuid.uuid4()))
|
||||
email: Mapped[str] = mapped_column(String(100), unique=True)
|
||||
username: Mapped[str] = mapped_column(String(20), unique=True)
|
||||
password: Mapped[str] = mapped_column(String(255))
|
||||
email_verified_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||
tenant_id: Mapped[str | None] = mapped_column(CHAR(36), nullable=True)
|
||||
status: Mapped[str] = mapped_column(String(20), default="ONBOARDING")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)
|
||||
updated_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, onupdate=datetime.now)
|
||||
deleted_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||
|
||||
profile: Mapped["UserProfile"] = relationship(back_populates="user", uselist=False)
|
||||
23
app/models/user_profile.py
Normal file
23
app/models/user_profile.py
Normal file
@ -0,0 +1,23 @@
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import DateTime, ForeignKey, String
|
||||
from sqlalchemy.dialects.mysql import CHAR
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from app.database import Base
|
||||
|
||||
|
||||
class UserProfile(Base):
|
||||
__tablename__ = "user_profiles"
|
||||
|
||||
id: Mapped[str] = mapped_column(CHAR(36), primary_key=True, default=lambda: str(uuid.uuid4()))
|
||||
user_id: Mapped[str] = mapped_column(CHAR(36), ForeignKey("users.id"), unique=True)
|
||||
full_name: Mapped[str] = mapped_column(String(200))
|
||||
phone: Mapped[str | None] = mapped_column(String(20), nullable=True)
|
||||
timezone: Mapped[str | None] = mapped_column(String(50), nullable=True, default="Asia/Jakarta")
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now)
|
||||
updated_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, onupdate=datetime.now)
|
||||
deleted_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
||||
|
||||
user: Mapped["User"] = relationship(back_populates="profile")
|
||||
17
app/schemas/__init__.py
Normal file
17
app/schemas/__init__.py
Normal file
@ -0,0 +1,17 @@
|
||||
from app.schemas.user import UserCreate, UserResponse
|
||||
from app.schemas.business_type import BusinessTypeCreate, BusinessTypeResponse
|
||||
from app.schemas.plan import PlanCreate, PlanResponse
|
||||
from app.schemas.tenant import TenantCreate, TenantResponse
|
||||
from app.schemas.subscription import SubscriptionResponse
|
||||
|
||||
__all__ = [
|
||||
"UserCreate",
|
||||
"UserResponse",
|
||||
"BusinessTypeCreate",
|
||||
"BusinessTypeResponse",
|
||||
"PlanCreate",
|
||||
"PlanResponse",
|
||||
"TenantCreate",
|
||||
"TenantResponse",
|
||||
"SubscriptionResponse",
|
||||
]
|
||||
21
app/schemas/business_type.py
Normal file
21
app/schemas/business_type.py
Normal file
@ -0,0 +1,21 @@
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class BusinessTypeCreate(BaseModel):
|
||||
code: str
|
||||
name: str
|
||||
description: str | None = None
|
||||
|
||||
|
||||
class BusinessTypeResponse(BaseModel):
|
||||
id: str
|
||||
code: str
|
||||
name: str
|
||||
description: str | None
|
||||
is_active: bool
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
25
app/schemas/plan.py
Normal file
25
app/schemas/plan.py
Normal file
@ -0,0 +1,25 @@
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class PlanCreate(BaseModel):
|
||||
code: str
|
||||
name: str
|
||||
description: str | None = None
|
||||
price: int
|
||||
limits: dict | None = None
|
||||
|
||||
|
||||
class PlanResponse(BaseModel):
|
||||
id: str
|
||||
code: str
|
||||
name: str
|
||||
description: str | None
|
||||
price: int
|
||||
limits: dict | None
|
||||
is_active: bool
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
16
app/schemas/subscription.py
Normal file
16
app/schemas/subscription.py
Normal file
@ -0,0 +1,16 @@
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class SubscriptionResponse(BaseModel):
|
||||
id: str
|
||||
tenant_id: str
|
||||
plan_id: str
|
||||
limits: dict | None
|
||||
status: str
|
||||
started_at: datetime
|
||||
ended_at: datetime | None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
29
app/schemas/tenant.py
Normal file
29
app/schemas/tenant.py
Normal file
@ -0,0 +1,29 @@
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class TenantCreate(BaseModel):
|
||||
name: str
|
||||
slug: str
|
||||
business_type_id: str
|
||||
phone: str | None = None
|
||||
address: str | None = None
|
||||
email: str | None = None
|
||||
plan_id: str
|
||||
limits: dict | None = None
|
||||
|
||||
|
||||
class TenantResponse(BaseModel):
|
||||
id: str
|
||||
name: str
|
||||
slug: str
|
||||
business_type_id: str
|
||||
phone: str | None
|
||||
address: str | None
|
||||
email: str | None
|
||||
status: str
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
24
app/schemas/user.py
Normal file
24
app/schemas/user.py
Normal file
@ -0,0 +1,24 @@
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel, EmailStr
|
||||
|
||||
|
||||
class UserCreate(BaseModel):
|
||||
email: EmailStr
|
||||
username: str
|
||||
password: str
|
||||
full_name: str
|
||||
phone: str | None = None
|
||||
timezone: str = "Asia/Jakarta"
|
||||
|
||||
|
||||
class UserResponse(BaseModel):
|
||||
id: str
|
||||
email: str
|
||||
username: str
|
||||
tenant_id: str | None
|
||||
status: str
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
12
main.py
12
main.py
@ -19,11 +19,13 @@ app.add_middleware(
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
app.include_router(auth_router)
|
||||
app.include_router(business_types_router)
|
||||
app.include_router(plans_router)
|
||||
app.include_router(tenants_router)
|
||||
app.include_router(subscriptions_router)
|
||||
API_PREFIX = "/v1"
|
||||
|
||||
app.include_router(auth_router, prefix=API_PREFIX)
|
||||
app.include_router(business_types_router, prefix=API_PREFIX)
|
||||
app.include_router(plans_router, prefix=API_PREFIX)
|
||||
app.include_router(tenants_router, prefix=API_PREFIX)
|
||||
app.include_router(subscriptions_router, prefix=API_PREFIX)
|
||||
|
||||
|
||||
@app.get("/")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user