Update routes/stylist.py
Browse files- routes/stylist.py +79 -66
routes/stylist.py
CHANGED
@@ -44,85 +44,79 @@ def verify_token(user_token: str) -> str:
|
|
44 |
else:
|
45 |
raise HTTPException(status_code=401, detail="Invalid or expired token")
|
46 |
|
47 |
-
def get_total_followers(user_id: str) -> int:
|
48 |
-
response = requests.get(
|
49 |
-
f"{SUPABASE_URL}/rest/v1/followers?following_id=eq.{user_id}&select=id",
|
50 |
-
headers=SUPABASE_HEADERS
|
51 |
-
)
|
52 |
-
if response.status_code == 200:
|
53 |
-
return len(response.json())
|
54 |
-
return 0
|
55 |
-
|
56 |
-
def get_total_subscribers(user_id: str) -> int:
|
57 |
-
response = requests.get(
|
58 |
-
f"{SUPABASE_URL}/rest/v1/Subscriptions?stylist_id=eq.{user_id}&active=eq.true&select=id",
|
59 |
-
headers=SUPABASE_HEADERS
|
60 |
-
)
|
61 |
-
if response.status_code == 200:
|
62 |
-
return len(response.json())
|
63 |
-
return 0
|
64 |
-
|
65 |
-
def calculate_growth(current: int, previous: int) -> Dict[str, Any]:
|
66 |
-
if previous == 0:
|
67 |
-
growth = 100 if current > 0 else 0
|
68 |
-
else:
|
69 |
-
growth = ((current - previous) / previous) * 100
|
70 |
-
return {
|
71 |
-
"trend": "up" if growth > 0 else "down" if growth < 0 else "neutral",
|
72 |
-
"percentage": round(growth, 1),
|
73 |
-
"formatted": f"{round(growth, 1)}%"
|
74 |
-
}
|
75 |
-
|
76 |
def get_monthly_revenue(account_id: str) -> List[Dict[str, Any]]:
|
77 |
ny_timezone = pytz.timezone('America/New_York')
|
78 |
now_ny = datetime.now(ny_timezone)
|
79 |
current_month = now_ny.month
|
80 |
current_year = now_ny.year
|
81 |
-
monthly_data =
|
82 |
for i in range(6):
|
83 |
target_date = now_ny - relativedelta(months=i)
|
84 |
month_num = target_date.month
|
85 |
month_name = target_date.strftime('%b')
|
86 |
year = target_date.year
|
87 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
start_date = now_ny - relativedelta(months=6)
|
89 |
start_timestamp = int(start_date.timestamp())
|
90 |
try:
|
91 |
-
transfers = stripe.Transfer.list(
|
|
|
|
|
|
|
|
|
92 |
for transfer in transfers.data:
|
93 |
transfer_date = datetime.fromtimestamp(transfer.created, ny_timezone)
|
94 |
month_num = transfer_date.month
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
except Exception as e:
|
105 |
logger.error(f"❌ Error getting monthly revenue: {str(e)}")
|
106 |
-
return monthly_data
|
107 |
|
108 |
-
def
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
|
127 |
@router.get("/dashboard")
|
128 |
def get_dashboard(user_token: str = Header(None, alias="User-key")):
|
@@ -132,20 +126,39 @@ def get_dashboard(user_token: str = Header(None, alias="User-key")):
|
|
132 |
user_id = verify_token(user_token)
|
133 |
logger.info(f"🔹 User verified. user_id: {user_id}")
|
134 |
user_data_url = f"{SUPABASE_URL}/rest/v1/User?id=eq.{user_id}"
|
135 |
-
response = requests.get(user_data_url, headers=
|
136 |
if response.status_code != 200 or not response.json():
|
137 |
raise HTTPException(status_code=404, detail="User not found")
|
138 |
user_data = response.json()[0]
|
139 |
stripe_id = user_data.get("stripe_id")
|
140 |
-
total_followers = get_total_followers(user_id)
|
141 |
-
total_subscribers = get_total_subscribers(user_id)
|
142 |
if not stripe_id:
|
143 |
-
return {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
balance_info = get_account_balance(stripe_id)
|
145 |
monthly_revenue = get_monthly_revenue(stripe_id)
|
146 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
147 |
except HTTPException as http_err:
|
148 |
raise http_err
|
149 |
except Exception as e:
|
150 |
logger.error(f"❌ Error: {str(e)}")
|
151 |
-
raise HTTPException(status_code=500, detail=str(e))
|
|
|
44 |
else:
|
45 |
raise HTTPException(status_code=401, detail="Invalid or expired token")
|
46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
def get_monthly_revenue(account_id: str) -> List[Dict[str, Any]]:
|
48 |
ny_timezone = pytz.timezone('America/New_York')
|
49 |
now_ny = datetime.now(ny_timezone)
|
50 |
current_month = now_ny.month
|
51 |
current_year = now_ny.year
|
52 |
+
monthly_data = {}
|
53 |
for i in range(6):
|
54 |
target_date = now_ny - relativedelta(months=i)
|
55 |
month_num = target_date.month
|
56 |
month_name = target_date.strftime('%b')
|
57 |
year = target_date.year
|
58 |
+
month_key = f"{year}-{month_num}"
|
59 |
+
is_current = (month_num == current_month and year == current_year)
|
60 |
+
monthly_data[month_key] = {
|
61 |
+
"month": month_num,
|
62 |
+
"name": month_name,
|
63 |
+
"current": is_current,
|
64 |
+
"amount": 0,
|
65 |
+
"growth": {"direction": "", "percentage": 0, "formatted": "0%"}
|
66 |
+
}
|
67 |
start_date = now_ny - relativedelta(months=6)
|
68 |
start_timestamp = int(start_date.timestamp())
|
69 |
try:
|
70 |
+
transfers = stripe.Transfer.list(
|
71 |
+
destination=account_id,
|
72 |
+
created={"gte": start_timestamp},
|
73 |
+
limit=100
|
74 |
+
)
|
75 |
for transfer in transfers.data:
|
76 |
transfer_date = datetime.fromtimestamp(transfer.created, ny_timezone)
|
77 |
month_num = transfer_date.month
|
78 |
+
year = transfer_date.year
|
79 |
+
month_key = f"{year}-{month_num}"
|
80 |
+
if month_key in monthly_data:
|
81 |
+
monthly_data[month_key]["amount"] += transfer.amount
|
82 |
+
result = list(monthly_data.values())
|
83 |
+
result.sort(key=lambda x: (current_month - x["month"]) % 12)
|
84 |
+
for i in range(1, len(result)):
|
85 |
+
prev_amount = result[i-1]["amount"]
|
86 |
+
curr_amount = result[i]["amount"]
|
87 |
+
if prev_amount > 0:
|
88 |
+
growth_percentage = ((curr_amount - prev_amount) / prev_amount) * 100
|
89 |
+
else:
|
90 |
+
growth_percentage = 100 if curr_amount > 0 else 0
|
91 |
+
direction = "up" if growth_percentage > 0 else "down"
|
92 |
+
result[i]["growth"] = {
|
93 |
+
"direction": direction,
|
94 |
+
"percentage": round(abs(growth_percentage), 2),
|
95 |
+
"formatted": f"{abs(growth_percentage):.1f}%"
|
96 |
+
}
|
97 |
+
return result
|
98 |
except Exception as e:
|
99 |
logger.error(f"❌ Error getting monthly revenue: {str(e)}")
|
100 |
+
return list(monthly_data.values())
|
101 |
|
102 |
+
def get_active_subscribers(stylist_id: str) -> List[Dict[str, Any]]:
|
103 |
+
url = f"{SUPABASE_URL}/rest/v1/Subscriptions?stylist_id=eq.{stylist_id}&active=eq.true&limit=30"
|
104 |
+
response = requests.get(url, headers=SUPABASE_HEADERS)
|
105 |
+
if response.status_code == 200:
|
106 |
+
subscriptions = response.json()
|
107 |
+
subscriber_ids = [sub["customer_id"] for sub in subscriptions]
|
108 |
+
if not subscriber_ids:
|
109 |
+
return []
|
110 |
+
user_data_url = f"{SUPABASE_URL}/rest/v1/User?id=in.({','.join(subscriber_ids)})"
|
111 |
+
user_response = requests.get(user_data_url, headers=SUPABASE_HEADERS)
|
112 |
+
if user_response.status_code == 200:
|
113 |
+
return [{
|
114 |
+
"id": user["id"],
|
115 |
+
"name": user["name"],
|
116 |
+
"avatar": user["avatar"],
|
117 |
+
"blurhash": user.get("blurhash", "")
|
118 |
+
} for user in user_response.json()]
|
119 |
+
return []
|
120 |
|
121 |
@router.get("/dashboard")
|
122 |
def get_dashboard(user_token: str = Header(None, alias="User-key")):
|
|
|
126 |
user_id = verify_token(user_token)
|
127 |
logger.info(f"🔹 User verified. user_id: {user_id}")
|
128 |
user_data_url = f"{SUPABASE_URL}/rest/v1/User?id=eq.{user_id}"
|
129 |
+
response = requests.get(user_data_url, headers=SUPABASE_HEADERS)
|
130 |
if response.status_code != 200 or not response.json():
|
131 |
raise HTTPException(status_code=404, detail="User not found")
|
132 |
user_data = response.json()[0]
|
133 |
stripe_id = user_data.get("stripe_id")
|
|
|
|
|
134 |
if not stripe_id:
|
135 |
+
return {
|
136 |
+
"stripe_id": None,
|
137 |
+
"available_balance": 0,
|
138 |
+
"pending_balance": 0,
|
139 |
+
"currency": "BRL",
|
140 |
+
"monthly_revenue": [],
|
141 |
+
"total_followers": 0,
|
142 |
+
"total_subscribers": 0,
|
143 |
+
"active_subscribers": []
|
144 |
+
}
|
145 |
balance_info = get_account_balance(stripe_id)
|
146 |
monthly_revenue = get_monthly_revenue(stripe_id)
|
147 |
+
total_followers = get_total_followers(user_id)
|
148 |
+
total_subscribers = get_total_subscribers(user_id)
|
149 |
+
active_subscribers = get_active_subscribers(user_id)
|
150 |
+
return {
|
151 |
+
"stripe_id": stripe_id,
|
152 |
+
"available_balance": balance_info["available_balance"],
|
153 |
+
"pending_balance": balance_info["pending_balance"],
|
154 |
+
"currency": balance_info["currency"],
|
155 |
+
"monthly_revenue": monthly_revenue,
|
156 |
+
"total_followers": total_followers,
|
157 |
+
"total_subscribers": total_subscribers,
|
158 |
+
"active_subscribers": active_subscribers
|
159 |
+
}
|
160 |
except HTTPException as http_err:
|
161 |
raise http_err
|
162 |
except Exception as e:
|
163 |
logger.error(f"❌ Error: {str(e)}")
|
164 |
+
raise HTTPException(status_code=500, detail=str(e))
|