discounts.py 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. from __future__ import annotations
  2. from datetime import datetime
  3. from typing import List, Optional
  4. from fastapi import APIRouter, HTTPException
  5. from pydantic import BaseModel, Field
  6. from app.db import get_pool
  7. router = APIRouter(tags=["discounts"])
  8. class DiscountIn(BaseModel):
  9. domain: str
  10. discount: float = Field(..., gt=0, le=1, description="折扣系数,如 0.8 表示八折")
  11. note: Optional[str] = None
  12. class DiscountOut(BaseModel):
  13. id: int
  14. domain: str
  15. discount: float
  16. note: Optional[str]
  17. created_at: datetime
  18. updated_at: datetime
  19. @router.get("/discounts", response_model=List[DiscountOut])
  20. async def list_discounts() -> List[DiscountOut]:
  21. pool = get_pool()
  22. rows = await pool.fetch("SELECT * FROM discounts ORDER BY updated_at DESC")
  23. return [DiscountOut(**dict(r)) for r in rows]
  24. @router.post("/discounts", response_model=DiscountOut, status_code=201)
  25. async def create_discount(body: DiscountIn) -> DiscountOut:
  26. pool = get_pool()
  27. row = await pool.fetchrow(
  28. """
  29. INSERT INTO discounts (domain, discount, note)
  30. VALUES ($1, $2, $3)
  31. ON CONFLICT (domain) DO UPDATE
  32. SET discount = EXCLUDED.discount,
  33. note = EXCLUDED.note,
  34. updated_at = NOW()
  35. RETURNING *
  36. """,
  37. body.domain, body.discount, body.note,
  38. )
  39. return DiscountOut(**dict(row))
  40. @router.put("/discounts/{discount_id}", response_model=DiscountOut)
  41. async def update_discount(discount_id: int, body: DiscountIn) -> DiscountOut:
  42. pool = get_pool()
  43. row = await pool.fetchrow(
  44. """
  45. UPDATE discounts SET domain=$1, discount=$2, note=$3, updated_at=NOW()
  46. WHERE id=$4 RETURNING *
  47. """,
  48. body.domain, body.discount, body.note, discount_id,
  49. )
  50. if not row:
  51. raise HTTPException(status_code=404, detail="不存在")
  52. return DiscountOut(**dict(row))
  53. @router.delete("/discounts/{discount_id}", status_code=204)
  54. async def delete_discount(discount_id: int) -> None:
  55. pool = get_pool()
  56. result = await pool.execute("DELETE FROM discounts WHERE id=$1", discount_id)
  57. if result == "DELETE 0":
  58. raise HTTPException(status_code=404, detail="不存在")