from __future__ import annotations from datetime import datetime from typing import List, Optional from fastapi import APIRouter, HTTPException from pydantic import BaseModel, Field from app.db import get_pool router = APIRouter(tags=["discounts"]) class DiscountIn(BaseModel): domain: str discount: float = Field(..., gt=0, le=1, description="折扣系数,如 0.8 表示八折") note: Optional[str] = None class DiscountOut(BaseModel): id: int domain: str discount: float note: Optional[str] created_at: datetime updated_at: datetime @router.get("/discounts", response_model=List[DiscountOut]) async def list_discounts() -> List[DiscountOut]: pool = get_pool() rows = await pool.fetch("SELECT * FROM discounts ORDER BY updated_at DESC") return [DiscountOut(**dict(r)) for r in rows] @router.post("/discounts", response_model=DiscountOut, status_code=201) async def create_discount(body: DiscountIn) -> DiscountOut: pool = get_pool() row = await pool.fetchrow( """ INSERT INTO discounts (domain, discount, note) VALUES ($1, $2, $3) ON CONFLICT (domain) DO UPDATE SET discount = EXCLUDED.discount, note = EXCLUDED.note, updated_at = NOW() RETURNING * """, body.domain, body.discount, body.note, ) return DiscountOut(**dict(row)) @router.put("/discounts/{discount_id}", response_model=DiscountOut) async def update_discount(discount_id: int, body: DiscountIn) -> DiscountOut: pool = get_pool() row = await pool.fetchrow( """ UPDATE discounts SET domain=$1, discount=$2, note=$3, updated_at=NOW() WHERE id=$4 RETURNING * """, body.domain, body.discount, body.note, discount_id, ) if not row: raise HTTPException(status_code=404, detail="不存在") return DiscountOut(**dict(row)) @router.delete("/discounts/{discount_id}", status_code=204) async def delete_discount(discount_id: int) -> None: pool = get_pool() result = await pool.execute("DELETE FROM discounts WHERE id=$1", discount_id) if result == "DELETE 0": raise HTTPException(status_code=404, detail="不存在")