- Add findagram.co React frontend with product search, brands, categories - Add findadispo.com React frontend with dispensary locator - Wire findagram to backend /api/az/* endpoints - Update category/brand links to route to /products with filters - Add k8s manifests for both frontends - Add multi-domain user support migrations 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
97 lines
2.2 KiB
Python
97 lines
2.2 KiB
Python
from pydantic import BaseModel
|
|
from datetime import datetime
|
|
from typing import Optional, List
|
|
|
|
|
|
class CategoryResponse(BaseModel):
|
|
id: int
|
|
name: str
|
|
slug: str
|
|
description: Optional[str] = None
|
|
icon: Optional[str] = None
|
|
image_url: Optional[str] = None
|
|
product_count: int = 0
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class BrandResponse(BaseModel):
|
|
id: int
|
|
name: str
|
|
slug: str
|
|
description: Optional[str] = None
|
|
logo_url: Optional[str] = None
|
|
website: Optional[str] = None
|
|
product_count: int = 0
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class DispensaryResponse(BaseModel):
|
|
id: int
|
|
name: str
|
|
slug: str
|
|
address: Optional[str] = None
|
|
city: Optional[str] = None
|
|
state: Optional[str] = None
|
|
phone: Optional[str] = None
|
|
website: Optional[str] = None
|
|
logo_url: Optional[str] = None
|
|
rating: Optional[float] = None
|
|
review_count: int = 0
|
|
latitude: Optional[float] = None
|
|
longitude: Optional[float] = None
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class ProductPriceResponse(BaseModel):
|
|
dispensary: DispensaryResponse
|
|
price: float
|
|
original_price: Optional[float] = None
|
|
in_stock: bool = True
|
|
has_deal: bool = False
|
|
deal_text: Optional[str] = None
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class ProductResponse(BaseModel):
|
|
id: int
|
|
name: str
|
|
slug: str
|
|
description: Optional[str] = None
|
|
image_url: Optional[str] = None
|
|
category: Optional[CategoryResponse] = None
|
|
brand: Optional[BrandResponse] = None
|
|
strain_type: Optional[str] = None
|
|
thc_percentage: Optional[float] = None
|
|
cbd_percentage: Optional[float] = None
|
|
weight: Optional[str] = None
|
|
lowest_price: Optional[float] = None
|
|
avg_price: Optional[float] = None
|
|
has_deal: bool = False
|
|
deal_text: Optional[str] = None
|
|
original_price: Optional[float] = None
|
|
dispensary_count: int = 0
|
|
created_at: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class ProductDetailResponse(ProductResponse):
|
|
prices: List[ProductPriceResponse] = []
|
|
|
|
|
|
class ProductListResponse(BaseModel):
|
|
products: List[ProductResponse]
|
|
total: int
|
|
page: int
|
|
per_page: int
|
|
total_pages: int
|