Spaces:
Sleeping
Sleeping
Download app/api/billing.py from Himankpro/Idk: direct link, hf CLI and curl.
- Browser
- Download file 5.11 kB
-
https://huggingface.co/spaces/Himankpro/Idk/resolve/main/app/api/billing.py
- Command line
-
hf download hf://spaces/Himankpro/Idk/app/api/billing.py
-
curl -L -o billing.py https://huggingface.co/spaces/Himankpro/Idk/resolve/main/app/api/billing.py
5.11 kB
| """Razorpay order + verify; coupon waivers mint the same billing_token as paid checkout.""" | |
| from __future__ import annotations | |
| import traceback | |
| import uuid | |
| from flask import jsonify, request | |
| from . import billing_bp | |
| from ..config import Config | |
| from ..services.supabase_jobs import sync_enabled | |
| from ..utils.billing_token import coupon_codes_set, mint_billing_token | |
| from ..utils.logger import get_logger | |
| from ..utils.supabase_auth import resolve_pipeline_user_id | |
| logger = get_logger("mirofish.api.billing") | |
| def _razorpay_enabled() -> bool: | |
| return bool(Config.RAZORPAY_KEY_ID and Config.RAZORPAY_KEY_SECRET) | |
| def _require_pipeline_user_when_sync(): | |
| """Same identity as /api/pipeline/* so billing cannot succeed while start would 401.""" | |
| if request.method == "OPTIONS": | |
| return None | |
| if not sync_enabled(): | |
| return None | |
| uid, err = resolve_pipeline_user_id() | |
| if err or not uid: | |
| return ( | |
| jsonify( | |
| { | |
| "success": False, | |
| "error": err | |
| or "Unauthorized — sign in and ensure VITE_PIPELINE_CLIENT_SECRET matches server PIPELINE_CLIENT_SECRET (required to record runs in Supabase).", | |
| } | |
| ), | |
| 401, | |
| ) | |
| return None | |
| def billing_create_order(): | |
| """ | |
| JSON body: { "coupon": "optional" } | |
| - Valid coupon → { waived, billing_token } | |
| - Razorpay configured → { waived: false, key_id, order_id, amount, currency } | |
| - Razorpay not configured → dev bypass { waived, billing_token, dev_bypass } | |
| """ | |
| try: | |
| gate = _require_pipeline_user_when_sync() | |
| if gate: | |
| return gate | |
| data = request.get_json(silent=True) or {} | |
| coupon = (data.get("coupon") or "").strip().upper() | |
| codes = coupon_codes_set() | |
| if coupon and coupon in codes: | |
| tok = mint_billing_token(source="coupon") | |
| return jsonify({"success": True, "data": {"waived": True, "billing_token": tok}}) | |
| if not _razorpay_enabled(): | |
| tok = mint_billing_token(source="dev_bypass") | |
| return jsonify( | |
| { | |
| "success": True, | |
| "data": {"waived": True, "billing_token": tok, "dev_bypass": True}, | |
| } | |
| ) | |
| import razorpay | |
| client = razorpay.Client(auth=(Config.RAZORPAY_KEY_ID, Config.RAZORPAY_KEY_SECRET)) | |
| receipt = "mf_" + str(uuid.uuid4()).replace("-", "")[:24] | |
| order = client.order.create( | |
| { | |
| "amount": Config.BILLING_AMOUNT_MINOR, | |
| "currency": Config.BILLING_CURRENCY, | |
| "receipt": receipt, | |
| "payment_capture": 1, | |
| } | |
| ) | |
| return jsonify( | |
| { | |
| "success": True, | |
| "data": { | |
| "waived": False, | |
| "key_id": Config.RAZORPAY_KEY_ID, | |
| "order_id": order["id"], | |
| "amount": int(order["amount"]), | |
| "currency": str(order["currency"]), | |
| }, | |
| } | |
| ) | |
| except Exception as e: | |
| logger.error(traceback.format_exc()) | |
| return jsonify({"success": False, "error": str(e)}), 500 | |
| def billing_verify(): | |
| """JSON: razorpay_payment_id, razorpay_order_id, razorpay_signature → billing_token.""" | |
| try: | |
| gate = _require_pipeline_user_when_sync() | |
| if gate: | |
| return gate | |
| if not _razorpay_enabled(): | |
| return jsonify({"success": False, "error": "Razorpay is not configured"}), 503 | |
| import razorpay | |
| from razorpay.errors import SignatureVerificationError | |
| data = request.get_json(silent=True) or {} | |
| payment_id = (data.get("razorpay_payment_id") or "").strip() | |
| order_id = (data.get("razorpay_order_id") or "").strip() | |
| signature = (data.get("razorpay_signature") or "").strip() | |
| if not payment_id or not order_id or not signature: | |
| return jsonify({"success": False, "error": "Missing payment fields"}), 400 | |
| client = razorpay.Client(auth=(Config.RAZORPAY_KEY_ID, Config.RAZORPAY_KEY_SECRET)) | |
| try: | |
| client.utility.verify_payment_signature( | |
| { | |
| "razorpay_order_id": order_id, | |
| "razorpay_payment_id": payment_id, | |
| "razorpay_signature": signature, | |
| } | |
| ) | |
| except SignatureVerificationError: | |
| return jsonify({"success": False, "error": "Invalid payment signature"}), 400 | |
| tok = mint_billing_token(source="razorpay") | |
| return jsonify({"success": True, "data": {"billing_token": tok}}) | |
| except Exception as e: | |
| logger.error(traceback.format_exc()) | |
| return jsonify({"success": False, "error": str(e)}), 500 | |