Files
AutonetSellCar Deploy c9fd7611a7 feat: Add banner toggle and soldout tracking to Cars page
- Add is_banner, soldout fields to Car model
- Add banner toggle API (POST /hero-banners/admin/toggle/{car_id})
- Add soldout APIs (POST/DELETE /cars/{car_id}/soldout)
- Add nightly soldout checker in agent (runs at 3:00 AM)
- Update Local Cars UI with banner checkbox and status column
- Remove hero-banners admin page (functionality moved to Cars page)
- Banner cars sorted to top with purple background
- Soldout cars displayed with gray overlay

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-31 12:50:40 +09:00

190 lines
5.0 KiB
Python

from pydantic import BaseModel
from typing import Optional, List, Any
from datetime import datetime
from decimal import Decimal
# CarSpecification Schema
class CarSpecificationResponse(BaseModel):
id: int
car_id: int
manufacturer: Optional[str] = None
model_name: Optional[str] = None
grade: Optional[str] = None
model_year: Optional[str] = None
displacement: Optional[int] = None
fuel_type: Optional[str] = None
transmission: Optional[str] = None
drive_type: Optional[str] = None
max_power: Optional[str] = None
max_torque: Optional[str] = None
fuel_efficiency: Optional[str] = None
body_type: Optional[str] = None
door_count: Optional[int] = None
seating_capacity: Optional[int] = None
length: Optional[int] = None
width: Optional[int] = None
height: Optional[int] = None
wheelbase: Optional[int] = None
curb_weight: Optional[int] = None
safety_options: Optional[List[str]] = None
comfort_options: Optional[List[str]] = None
exterior_options: Optional[List[str]] = None
interior_options: Optional[List[str]] = None
raw_data: Optional[Any] = None
class Config:
from_attributes = True
# CarMaker Schemas
class CarMakerCreate(BaseModel):
code: str
name: str
name_en: Optional[str] = None
class CarMakerResponse(BaseModel):
id: int
code: str
name: str
name_en: Optional[str] = None
class Config:
from_attributes = True
# CarModel Schemas
class CarModelCreate(BaseModel):
code: str
maker_id: int
name: str
name_en: Optional[str] = None
class CarModelResponse(BaseModel):
id: int
code: str
maker_id: int
name: str
name_en: Optional[str] = None
class Config:
from_attributes = True
# CarImage Schemas
class CarImageCreate(BaseModel):
url: Optional[str] = None
local_path: Optional[str] = None
is_main: bool = False
sort_order: int = 0
class CarImageResponse(BaseModel):
id: int
url: Optional[str] = None
local_path: Optional[str] = None
is_main: bool
sort_order: int
class Config:
from_attributes = True
# Car Schemas
class CarCreate(BaseModel):
source: str = "carmodoo"
source_id: str
source_key: Optional[str] = None
maker_code: Optional[str] = None
model_code: Optional[str] = None
car_name: Optional[str] = None
year: Optional[int] = None
month: Optional[int] = None
mileage: Optional[int] = None
price_krw: Optional[int] = None
price_usd: Optional[Decimal] = None
fuel: Optional[str] = None
transmission: Optional[str] = None
color: Optional[str] = None
displacement: Optional[int] = None
car_number: Optional[str] = None
seize_count: int = 0
collateral_count: int = 0
check_num: Optional[str] = None
dealer_name: Optional[str] = None
dealer_phone: Optional[str] = None
shop_name: Optional[str] = None
memo: Optional[str] = None
images: List[CarImageCreate] = []
options: List[str] = []
class CarUpdate(BaseModel):
car_name: Optional[str] = None
year: Optional[int] = None
month: Optional[int] = None
mileage: Optional[int] = None
price_krw: Optional[int] = None
margin_krw: Optional[int] = None
margin_mn: Optional[int] = None
price_usd: Optional[Decimal] = None
fuel: Optional[str] = None
transmission: Optional[str] = None
color: Optional[str] = None
status: Optional[str] = None
is_displayed: Optional[bool] = None
is_banner: Optional[bool] = None
soldout: Optional[bool] = None
class CarResponse(BaseModel):
id: int
source: str
source_id: str
car_name: Optional[str] = None
year: Optional[int] = None
month: Optional[int] = None
mileage: Optional[int] = None
price_krw: Optional[int] = None
margin_krw: Optional[int] = 0
margin_mn: Optional[int] = 0
final_price_krw: Optional[int] = None # Computed: price_krw + margin_krw (for Korean users)
final_price_mn: Optional[int] = None # Computed: price_krw + margin_mn (for Mongolian users)
price_usd: Optional[Decimal] = None
is_displayed: bool = False
is_banner: bool = False
soldout: bool = False
fuel: Optional[str] = None
transmission: Optional[str] = None
color: Optional[str] = None
displacement: Optional[int] = None
car_number: Optional[str] = None
seize_count: int
collateral_count: int
check_num: Optional[str] = None
dealer_name: Optional[str] = None
dealer_description: Optional[str] = None
dealer_description_en: Optional[str] = None
dealer_description_mn: Optional[str] = None
dealer_description_ru: Optional[str] = None
status: str
created_at: datetime
updated_at: datetime
maker: Optional[CarMakerResponse] = None
model: Optional[CarModelResponse] = None
images: List[CarImageResponse] = []
specification: Optional[CarSpecificationResponse] = None
class Config:
from_attributes = True
class CarListResponse(BaseModel):
total: int
page: int
page_size: int
cars: List[CarResponse]