|
import stripe |
|
import logging |
|
import json |
|
import os |
|
import requests |
|
from fastapi import APIRouter, HTTPException |
|
from pydantic import BaseModel |
|
|
|
router = APIRouter() |
|
|
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") |
|
logger = logging.getLogger(__name__) |
|
|
|
stripe.api_key = "sk_test_51N6K5JB9VMe0qzbOjlJvMEsfdQyrFgV49vRaeErtmhrzHV3Cu3f5jMDJmrhKdI5uqvpHubjkmwDQgMOtCEmz19t800AouH7W6g" |
|
stripe.api_version = "2023-10-16" |
|
|
|
|
|
SUPABASE_URL = "https://ussxqnifefkgkaumjann.supabase.co" |
|
SUPABASE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InVzc3hxbmlmZWZrZ2thdW1qYW5uIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Mzc2NTE2MjMsImV4cCI6MjA1MzIyNzYyM30.SWb6lh3foBp8MrZaHpjt5kKkzXNyBYh3vgfayIM7bzs" |
|
SUPABASE_HEADERS = { |
|
"apikey": SUPABASE_KEY, |
|
"Authorization": f"Bearer {SUPABASE_KEY}", |
|
"Content-Type": "application/json" |
|
} |
|
|
|
class SubscriptionRequest(BaseModel): |
|
user_id: str |
|
stylist_id: str |
|
|
|
@router.post("/create_checkout_session") |
|
def create_checkout_session(data: SubscriptionRequest): |
|
try: |
|
|
|
response = requests.get( |
|
f"{SUPABASE_URL}/rest/v1/User?id=eq.{data.stylist_id}", |
|
headers=SUPABASE_HEADERS |
|
) |
|
|
|
stylist_data = response.json() |
|
if not stylist_data: |
|
raise HTTPException(status_code=404, detail="Stylist not found") |
|
|
|
stylist = stylist_data[0] |
|
|
|
|
|
stylist_name = stylist["name"] |
|
stylist_price = stylist["price"] |
|
stylist_avatar = stylist["avatar"] |
|
consultations = stylist["consultations"] |
|
|
|
if not stylist_price or not consultations: |
|
raise HTTPException(status_code=400, detail="Stylist has not set up their pricing or consultations") |
|
|
|
|
|
session = stripe.checkout.Session.create( |
|
success_url="https://yourdomain.com/success", |
|
cancel_url="https://yourdomain.com/cancel", |
|
payment_method_types=["card"], |
|
mode="subscription", |
|
line_items=[ |
|
{ |
|
"price_data": { |
|
"currency": "brl", |
|
"product_data": { |
|
"name": f"{stylist_name}'s Subscription", |
|
"description": f"✔ {consultations} video call consultations per month", |
|
"images": [stylist_avatar], |
|
}, |
|
"unit_amount": stylist_price, |
|
"recurring": {"interval": "month"} |
|
}, |
|
"quantity": 1 |
|
} |
|
], |
|
subscription_data={ |
|
"metadata": { |
|
"user_id": data.user_id, |
|
"stylist_id": data.stylist_id, |
|
"consultations_per_month": consultations |
|
} |
|
} |
|
) |
|
|
|
return { |
|
"message": "Checkout session created successfully!", |
|
"checkout_url": session.url |
|
} |
|
|
|
except Exception as e: |
|
logger.error(f"Error creating checkout session: {e}") |
|
raise HTTPException(status_code=500, detail="Error creating checkout session.") |
|
|
|
|
|
@router.post("/webhook") |
|
async def stripe_webhook(request: Request): |
|
payload = await request.body() |
|
headers = dict(request.headers) |
|
event = None |
|
|
|
try: |
|
event = stripe.Event.construct_from(json.loads(payload), stripe.api_key) |
|
except Exception as e: |
|
logger.error(f"⚠️ Error processing webhook: {e}") |
|
raise HTTPException(status_code=400, detail="Webhook error") |
|
|
|
logger.info(f"🔹 Event received: {event['type']}") |
|
|
|
if event["type"] == "invoice.payment_succeeded": |
|
invoice = event["data"]["object"] |
|
subscription_id = invoice.get("subscription") |
|
|
|
subscription = stripe.Subscription.retrieve(subscription_id) |
|
user_id = subscription.metadata.get("user_id") |
|
stylist_id = subscription.metadata.get("stylist_id") |
|
|
|
amount = invoice["amount_paid"] |
|
stylist_share = int(amount * 0.8) |
|
platform_share = amount - stylist_share |
|
|
|
|
|
try: |
|
transfer = stripe.Transfer.create( |
|
amount=stylist_share, |
|
currency="brl", |
|
destination=stylist_id, |
|
description=f"Payment for stylist {stylist_id} - Subscription", |
|
) |
|
logger.info(f"💸 Transfer successful: R${stylist_share / 100:.2f} BRL to {stylist_id}") |
|
transfer_status = "Completed" |
|
except Exception as e: |
|
logger.error(f"🚨 Transfer error for stylist {stylist_id}: {e}") |
|
transfer_status = "Failed" |
|
|
|
return { |
|
"status": "Payment processed successfully!", |
|
"user_id": user_id, |
|
"stylist_id": stylist_id, |
|
"total_paid": amount / 100, |
|
"stylist_share": stylist_share / 100, |
|
"platform_share": platform_share / 100, |
|
"transfer_status": transfer_status |
|
} |
|
|
|
return {"status": "Event received, no action needed."} |
|
|
|
|
|
@router.post("/cancel_subscription") |
|
def cancel_subscription(data: CancelSubscriptionRequest): |
|
try: |
|
subscription = stripe.Subscription.modify( |
|
data.subscription_id, |
|
cancel_at_period_end=True, |
|
) |
|
return {"status": "Subscription will be canceled at period end"} |
|
except Exception as e: |
|
raise HTTPException(status_code=500, detail=str(e)) |