deploy: credits.py
Browse files- credits.py +37 -0
credits.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fastapi import HTTPException
|
| 2 |
+
from db import supabase
|
| 3 |
+
from datetime import datetime, timezone
|
| 4 |
+
|
| 5 |
+
PLAN_CREDITS = {"free": 100, "hobby": 5_000, "team": 25_000,
|
| 6 |
+
"business": 100_000, "enterprise": 999_999_999}
|
| 7 |
+
|
| 8 |
+
async def check_and_deduct_credits(user_id: str, cost: int) -> int:
|
| 9 |
+
res = (supabase.table("users")
|
| 10 |
+
.select("credits_remaining,plan,credits_reset_at")
|
| 11 |
+
.eq("id", user_id).single().execute())
|
| 12 |
+
user = res.data
|
| 13 |
+
if not user: raise HTTPException(404, "User not found")
|
| 14 |
+
|
| 15 |
+
if user["plan"] == "free":
|
| 16 |
+
reset = datetime.fromisoformat(user["credits_reset_at"])
|
| 17 |
+
now = datetime.now(timezone.utc)
|
| 18 |
+
if now > reset:
|
| 19 |
+
supabase.table("users").update({
|
| 20 |
+
"credits_remaining": PLAN_CREDITS["free"],
|
| 21 |
+
"credits_reset_at": now.replace(hour=0,minute=0,second=0).isoformat()
|
| 22 |
+
}).eq("id", user_id).execute()
|
| 23 |
+
user["credits_remaining"] = PLAN_CREDITS["free"]
|
| 24 |
+
|
| 25 |
+
if user["credits_remaining"] < cost:
|
| 26 |
+
raise HTTPException(429, {
|
| 27 |
+
"error": "Out of credits", "plan": user["plan"],
|
| 28 |
+
"credits_remaining": user["credits_remaining"],
|
| 29 |
+
"upgrade_url": "https://nurricai.com/pricing"})
|
| 30 |
+
|
| 31 |
+
new_bal = user["credits_remaining"] - cost
|
| 32 |
+
supabase.table("users").update({"credits_remaining": new_bal}).eq("id", user_id).execute()
|
| 33 |
+
supabase.table("usage_logs").insert({
|
| 34 |
+
"user_id": user_id, "credits_used": cost,
|
| 35 |
+
"timestamp": datetime.now(timezone.utc).isoformat()
|
| 36 |
+
}).execute()
|
| 37 |
+
return new_bal
|