eheguy commited on
Commit
21614c2
·
1 Parent(s): f019835

Update to Razorpay Orders checkout

Browse files
Files changed (2) hide show
  1. main.py +46 -54
  2. usage.py +2 -3
main.py CHANGED
@@ -15,7 +15,7 @@ if not os.getenv("GROQ_API_KEY") and os.getenv("HF_TOKEN"):
15
  os.environ["GROQ_API_KEY"] = os.getenv("HF_TOKEN")
16
 
17
  from humanizer import humanize_text
18
- from usage import check_usage_limit, increment_usage, get_user_profile, update_user_subscription, cancel_user_subscription
19
 
20
  from fastapi.middleware.cors import CORSMiddleware
21
  from fastapi import Request
@@ -74,7 +74,14 @@ class HumanizeResponse(BaseModel):
74
  purpose: str
75
  usage: dict # { count, limit, plan }
76
 
77
- class CreateSubscriptionRequest(BaseModel):
 
 
 
 
 
 
 
78
  user_id: str
79
  plan: str
80
 
@@ -136,72 +143,57 @@ async def get_user_plan(user_id: str):
136
  raise HTTPException(status_code=404, detail="User not found")
137
  return {"plan": profile.get("plan", "free")}
138
 
139
- @app.post("/create-subscription")
140
- async def create_subscription(request: CreateSubscriptionRequest):
 
 
141
  if request.plan not in ["starter", "pro"]:
142
  raise HTTPException(status_code=400, detail="Invalid plan")
143
 
144
- plan_id = RAZORPAY_STARTER_PLAN_ID if request.plan == "starter" else RAZORPAY_PRO_PLAN_ID
 
 
 
 
145
 
146
  try:
147
- subscription_data = {
148
- "plan_id": plan_id,
149
- "customer_notify": 1,
150
- "total_count": 12,
151
- "notes": {
152
- "user_id": request.user_id
153
- }
 
 
 
 
154
  }
155
- subscription = razorpay_client.subscription.create(subscription_data)
156
- return {"subscription_id": subscription["id"], "key_id": RAZORPAY_KEY_ID}
157
  except Exception as e:
158
  raise HTTPException(status_code=500, detail=str(e))
159
 
160
- @app.post("/razorpay-webhook")
161
- async def razorpay_webhook(request: Request):
162
- payload = await request.body()
163
- signature = request.headers.get("X-Razorpay-Signature", "")
164
-
165
- if not RAZORPAY_WEBHOOK_SECRET:
166
- raise HTTPException(status_code=500, detail="Webhook secret not configured")
167
-
168
- expected_signature = hmac.new(
169
- key=RAZORPAY_WEBHOOK_SECRET.encode('utf-8'),
170
- msg=payload,
171
- digestmod='sha256'
172
- ).hexdigest()
173
-
174
- if not hmac.compare_digest(expected_signature, signature):
175
- raise HTTPException(status_code=400, detail="Invalid signature")
176
 
177
  try:
178
- data = json.loads(payload.decode('utf-8'))
179
- event = data.get("event")
 
 
 
180
 
181
- if event == "subscription.charged":
182
- sub_entity = data.get("payload", {}).get("subscription", {}).get("entity", {})
183
- user_id = sub_entity.get("notes", {}).get("user_id")
184
- subscription_id = sub_entity.get("id")
185
- plan_id = sub_entity.get("plan_id")
 
186
 
187
- plan_name = "free"
188
- if plan_id == RAZORPAY_STARTER_PLAN_ID:
189
- plan_name = "starter"
190
- elif plan_id == RAZORPAY_PRO_PLAN_ID:
191
- plan_name = "pro"
192
-
193
- if user_id and plan_name != "free":
194
- profile = get_user_profile(user_id)
195
- if profile and profile.get("plan") != plan_name:
196
- update_user_subscription(user_id, plan_name, subscription_id)
197
-
198
- elif event in ["subscription.cancelled", "subscription.halted"]:
199
- sub_entity = data.get("payload", {}).get("subscription", {}).get("entity", {})
200
- user_id = sub_entity.get("notes", {}).get("user_id")
201
- if user_id:
202
- cancel_user_subscription(user_id)
203
-
204
  return {"status": "ok"}
 
 
205
  except Exception as e:
206
  raise HTTPException(status_code=500, detail=str(e))
207
 
 
15
  os.environ["GROQ_API_KEY"] = os.getenv("HF_TOKEN")
16
 
17
  from humanizer import humanize_text
18
+ from usage import check_usage_limit, increment_usage, get_user_profile, upgrade_user_plan, cancel_user_subscription
19
 
20
  from fastapi.middleware.cors import CORSMiddleware
21
  from fastapi import Request
 
74
  purpose: str
75
  usage: dict # { count, limit, plan }
76
 
77
+ class CreateOrderRequest(BaseModel):
78
+ user_id: str
79
+ plan: str
80
+
81
+ class VerifyPaymentRequest(BaseModel):
82
+ razorpay_order_id: str
83
+ razorpay_payment_id: str
84
+ razorpay_signature: str
85
  user_id: str
86
  plan: str
87
 
 
143
  raise HTTPException(status_code=404, detail="User not found")
144
  return {"plan": profile.get("plan", "free")}
145
 
146
+ @app.post("/api/create-order")
147
+ async def create_order(request: CreateOrderRequest):
148
+ if not request.user_id:
149
+ raise HTTPException(status_code=401, detail="Unauthorized")
150
  if request.plan not in ["starter", "pro"]:
151
  raise HTTPException(status_code=400, detail="Invalid plan")
152
 
153
+ # Map plans to amounts (e.g. Starter = $9 = ₹750 = 75000 paise)
154
+ amount = 75000 if request.plan == "starter" else 150000
155
+
156
+ if amount < 100:
157
+ raise HTTPException(status_code=400, detail="Amount must be at least 100 paise")
158
 
159
  try:
160
+ order_data = {
161
+ "amount": amount,
162
+ "currency": "INR",
163
+ "receipt": request.user_id
164
+ }
165
+ order = razorpay_client.order.create(order_data)
166
+ return {
167
+ "order_id": order["id"],
168
+ "amount": amount,
169
+ "currency": "INR",
170
+ "key_id": RAZORPAY_KEY_ID
171
  }
 
 
172
  except Exception as e:
173
  raise HTTPException(status_code=500, detail=str(e))
174
 
175
+ @app.post("/api/verify-payment")
176
+ async def verify_payment(request: VerifyPaymentRequest):
177
+ if not request.razorpay_order_id or not request.razorpay_payment_id or not request.razorpay_signature:
178
+ raise HTTPException(status_code=400, detail="Missing required fields")
 
 
 
 
 
 
 
 
 
 
 
 
179
 
180
  try:
181
+ expected_signature = hmac.new(
182
+ key=RAZORPAY_KEY_SECRET.encode('utf-8'),
183
+ msg=(request.razorpay_order_id + "|" + request.razorpay_payment_id).encode('utf-8'),
184
+ digestmod='sha256'
185
+ ).hexdigest()
186
 
187
+ if not hmac.compare_digest(expected_signature, request.razorpay_signature):
188
+ raise HTTPException(status_code=400, detail="Invalid signature")
189
+
190
+ profile = get_user_profile(request.user_id)
191
+ if profile and profile.get("plan") != request.plan:
192
+ upgrade_user_plan(request.user_id, request.plan)
193
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  return {"status": "ok"}
195
+ except HTTPException:
196
+ raise
197
  except Exception as e:
198
  raise HTTPException(status_code=500, detail=str(e))
199
 
usage.py CHANGED
@@ -54,12 +54,11 @@ def increment_usage(user_id: str) -> None:
54
  {"humanization_count": new_count}
55
  ).eq("id", user_id).execute()
56
 
57
- def update_user_subscription(user_id: str, plan: str, subscription_id: str) -> None:
58
- """Update user plan and reset usage."""
59
  client = get_supabase()
60
  client.table("profiles").update({
61
  "plan": plan,
62
- "razorpay_subscription_id": subscription_id,
63
  "humanization_count": 0
64
  }).eq("id", user_id).execute()
65
 
 
54
  {"humanization_count": new_count}
55
  ).eq("id", user_id).execute()
56
 
57
+ def upgrade_user_plan(user_id: str, plan: str) -> None:
58
+ """Update user plan for a one-time order and reset usage."""
59
  client = get_supabase()
60
  client.table("profiles").update({
61
  "plan": plan,
 
62
  "humanization_count": 0
63
  }).eq("id", user_id).execute()
64