feat: 开发采集、采集箱和商品编辑功能
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
"""Ozon 类目/属性字典代理(服务端持店铺凭证调用 Ozon,前端不直连)。"""
|
||||
from __future__ import annotations
|
||||
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from core.security import decrypt_secret
|
||||
from db import get_db
|
||||
from deps import get_current_user
|
||||
from models import Shop
|
||||
from services.ozon_client import OzonClient, OzonAPIError
|
||||
|
||||
router = APIRouter(prefix="/api/categories", tags=["categories"])
|
||||
|
||||
|
||||
class ShopRef(BaseModel):
|
||||
shop_id: str
|
||||
lang: str = "ZH_HANS" # 中文类目
|
||||
|
||||
|
||||
async def _client(shop_id: str, db: AsyncSession) -> OzonClient:
|
||||
shop = await db.get(Shop, UUID(shop_id))
|
||||
if shop is None:
|
||||
raise HTTPException(status_code=404, detail="店铺不存在")
|
||||
return OzonClient(decrypt_secret(shop.client_id_enc), decrypt_secret(shop.api_key_enc))
|
||||
|
||||
|
||||
def _unwrap(result: dict) -> dict:
|
||||
return result.get("result", result)
|
||||
|
||||
|
||||
@router.post("/tree")
|
||||
async def category_tree(
|
||||
body: ShopRef,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
_user: dict = Depends(get_current_user),
|
||||
):
|
||||
client = await _client(body.shop_id, db)
|
||||
try:
|
||||
result = await client.post("/v1/description-category/tree", {"language": body.lang})
|
||||
return _unwrap(result)
|
||||
except OzonAPIError as exc:
|
||||
raise HTTPException(status_code=502, detail=exc.detail)
|
||||
|
||||
|
||||
class AttributeQuery(BaseModel):
|
||||
shop_id: str
|
||||
type_id: int
|
||||
lang: str = "ZH_HANS"
|
||||
|
||||
|
||||
@router.post("/{category_id}/attributes")
|
||||
async def category_attributes(
|
||||
category_id: int,
|
||||
body: AttributeQuery,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
_user: dict = Depends(get_current_user),
|
||||
):
|
||||
client = await _client(body.shop_id, db)
|
||||
try:
|
||||
result = await client.post(
|
||||
"/v1/description-category/attribute",
|
||||
{
|
||||
"description_category_id": category_id,
|
||||
"type_id": body.type_id,
|
||||
"language": body.lang,
|
||||
},
|
||||
)
|
||||
return _unwrap(result)
|
||||
except OzonAPIError as exc:
|
||||
raise HTTPException(status_code=502, detail=exc.detail)
|
||||
|
||||
|
||||
class ValueQuery(BaseModel):
|
||||
shop_id: str
|
||||
category_id: int
|
||||
type_id: int
|
||||
q: str | None = None
|
||||
limit: int = 100
|
||||
last_value_id: int | None = None
|
||||
lang: str = "ZH_HANS"
|
||||
|
||||
|
||||
@router.post("/attribute/{attribute_id}/values")
|
||||
async def attribute_values(
|
||||
attribute_id: int,
|
||||
body: ValueQuery,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
_user: dict = Depends(get_current_user),
|
||||
):
|
||||
client = await _client(body.shop_id, db)
|
||||
try:
|
||||
if body.q and len(body.q) >= 2:
|
||||
result = await client.post(
|
||||
"/v1/description-category/attribute/values/search",
|
||||
{
|
||||
"attribute_id": attribute_id,
|
||||
"description_category_id": body.category_id,
|
||||
"type_id": body.type_id,
|
||||
"limit": body.limit,
|
||||
"value": body.q,
|
||||
},
|
||||
)
|
||||
else:
|
||||
result = await client.post(
|
||||
"/v1/description-category/attribute/values",
|
||||
{
|
||||
"attribute_id": attribute_id,
|
||||
"description_category_id": body.category_id,
|
||||
"type_id": body.type_id,
|
||||
"limit": body.limit,
|
||||
"last_value_id": body.last_value_id or 0,
|
||||
"language": body.lang,
|
||||
},
|
||||
)
|
||||
return result # values 返回 {result, has_next}
|
||||
except OzonAPIError as exc:
|
||||
raise HTTPException(status_code=502, detail=exc.detail)
|
||||
Reference in New Issue
Block a user