from pydantic import BaseModel, Field, EmailStr, validator from typing import List, Optional from datetime import datetime from bson import ObjectId from pydantic import ConfigDict from typing import Any, ClassVar class PyObjectId(ObjectId): @classmethod def __get_pydantic_core_schema__( cls, _source_type: Any, _handler: Any ) -> Any: from pydantic_core import core_schema return core_schema.json_or_python_schema( python_schema=core_schema.is_instance_schema(ObjectId), json_schema=core_schema.StringSchema(), serialization=core_schema.to_string_ser_schema(), ) class MongoBaseModel(BaseModel): id: PyObjectId = Field(default_factory=PyObjectId, alias="_id") model_config = ConfigDict( populate_by_name=True, arbitrary_types_allowed=True, json_encoders={ObjectId: str} ) class Item(MongoBaseModel): name: str price: float quantity: int unit: str related_items: List[str] = [] class OrderItem(BaseModel): item_id: PyObjectId quantity: int price_at_order: float class Order(MongoBaseModel): user_id: PyObjectId items: List[OrderItem] total_amount: float payment_method: Optional[str] = None payment_status: str = "pending" order_status: str = "created" created_at: datetime = Field(default_factory=datetime.utcnow) updated_at: Optional[datetime] = None discount_applied: Optional[float] = None notes: Optional[str] = None @validator('order_status') def valid_order_status(cls, v): allowed_statuses = ["created", "processing", "shipped", "delivered", "cancelled"] if v not in allowed_statuses: raise ValueError(f"Invalid order status. Must be one of: { ', '.join(allowed_statuses)}") return v @validator('payment_status') def valid_payment_status(cls, v): allowed_statuses = ["pending", "paid", "refunded", "failed"] if v not in allowed_statuses: raise ValueError(f"Invalid payment status. Must be one of: { ', '.join(allowed_statuses)}") return v class UserBase(BaseModel): username: str email: EmailStr full_name: str is_active: bool = True is_superuser: bool = False class UserCreate(UserBase): password: str class UserInDB(UserBase, MongoBaseModel): hashed_password: str class User(UserBase, MongoBaseModel): pass class Token(BaseModel): access_token: str token_type: str class TokenData(BaseModel): username: Optional[str] = None