Update routes/users.py
Browse files- routes/users.py +20 -18
routes/users.py
CHANGED
@@ -205,43 +205,45 @@ async def get_recent_users_endpoint(
|
|
205 |
|
206 |
from datetime import datetime
|
207 |
|
|
|
|
|
208 |
@router.get("/admin/user-transfers")
|
209 |
async def get_user_transfer_history(
|
210 |
user_token: str = Header(None, alias="User-key"),
|
211 |
-
user_id: str = Query(..., description="ID
|
212 |
):
|
213 |
"""
|
214 |
-
|
215 |
"""
|
216 |
try:
|
217 |
-
#
|
218 |
await verify_token_with_permissions(user_token, "view_users")
|
219 |
|
220 |
-
#
|
221 |
user_url = f"{SUPABASE_URL}/rest/v1/User?id=eq.{user_id}&select=stripe_id"
|
222 |
async with aiohttp.ClientSession() as session:
|
223 |
async with session.get(user_url, headers=SUPABASE_HEADERS) as response:
|
224 |
if response.status != 200:
|
225 |
-
raise HTTPException(status_code=404, detail="
|
226 |
data = await response.json()
|
227 |
if not data or not data[0].get("stripe_id"):
|
228 |
-
raise HTTPException(status_code=404, detail="Stripe ID
|
229 |
stripe_id = data[0]["stripe_id"]
|
230 |
|
231 |
-
#
|
232 |
all_charges = stripe.Charge.list(customer=stripe_id, limit=100)
|
233 |
total_count = len(all_charges["data"])
|
234 |
recent_charges = sorted(all_charges["data"], key=lambda c: c["created"], reverse=True)[:10]
|
235 |
|
236 |
-
#
|
237 |
status_map = {
|
238 |
-
"succeeded": {"label": "
|
239 |
-
"pending": {"label": "
|
240 |
-
"failed": {"label": "
|
241 |
-
"canceled": {"label": "
|
242 |
}
|
243 |
|
244 |
-
#
|
245 |
async def fetch_stylist(stylist_id: str) -> Optional[Dict[str, Any]]:
|
246 |
url = f"{SUPABASE_URL}/rest/v1/User?id=eq.{stylist_id}&select=name,email,avatar"
|
247 |
async with aiohttp.ClientSession() as session:
|
@@ -252,7 +254,7 @@ async def get_user_transfer_history(
|
|
252 |
return data[0]
|
253 |
return None
|
254 |
|
255 |
-
#
|
256 |
transfers = []
|
257 |
tasks = []
|
258 |
|
@@ -270,8 +272,8 @@ async def get_user_transfer_history(
|
|
270 |
|
271 |
status_id = charge["status"]
|
272 |
status_info = status_map.get(status_id, {
|
273 |
-
"label": "
|
274 |
-
"color": "#9ca3af"
|
275 |
})
|
276 |
|
277 |
transfers.append({
|
@@ -300,5 +302,5 @@ async def get_user_transfer_history(
|
|
300 |
except HTTPException as he:
|
301 |
raise he
|
302 |
except Exception as e:
|
303 |
-
logger.error(f"❌
|
304 |
-
raise HTTPException(status_code=500, detail="
|
|
|
205 |
|
206 |
from datetime import datetime
|
207 |
|
208 |
+
from datetime import datetime
|
209 |
+
|
210 |
@router.get("/admin/user-transfers")
|
211 |
async def get_user_transfer_history(
|
212 |
user_token: str = Header(None, alias="User-key"),
|
213 |
+
user_id: str = Query(..., description="ID of the user in Supabase")
|
214 |
):
|
215 |
"""
|
216 |
+
Returns the last 10 payments of the user with metadata, stylist info and formatted status.
|
217 |
"""
|
218 |
try:
|
219 |
+
# Verify permissions
|
220 |
await verify_token_with_permissions(user_token, "view_users")
|
221 |
|
222 |
+
# Get user's stripe_id
|
223 |
user_url = f"{SUPABASE_URL}/rest/v1/User?id=eq.{user_id}&select=stripe_id"
|
224 |
async with aiohttp.ClientSession() as session:
|
225 |
async with session.get(user_url, headers=SUPABASE_HEADERS) as response:
|
226 |
if response.status != 200:
|
227 |
+
raise HTTPException(status_code=404, detail="User not found")
|
228 |
data = await response.json()
|
229 |
if not data or not data[0].get("stripe_id"):
|
230 |
+
raise HTTPException(status_code=404, detail="Stripe ID not found for this user")
|
231 |
stripe_id = data[0]["stripe_id"]
|
232 |
|
233 |
+
# Fetch charges from Stripe
|
234 |
all_charges = stripe.Charge.list(customer=stripe_id, limit=100)
|
235 |
total_count = len(all_charges["data"])
|
236 |
recent_charges = sorted(all_charges["data"], key=lambda c: c["created"], reverse=True)[:10]
|
237 |
|
238 |
+
# Status mapping (id → label + color)
|
239 |
status_map = {
|
240 |
+
"succeeded": {"label": "Succeeded", "color": "#22c55e"},
|
241 |
+
"pending": {"label": "Pending", "color": "#eab308"},
|
242 |
+
"failed": {"label": "Failed", "color": "#ef4444"},
|
243 |
+
"canceled": {"label": "Canceled", "color": "#6b7280"},
|
244 |
}
|
245 |
|
246 |
+
# Helper to fetch stylist info
|
247 |
async def fetch_stylist(stylist_id: str) -> Optional[Dict[str, Any]]:
|
248 |
url = f"{SUPABASE_URL}/rest/v1/User?id=eq.{stylist_id}&select=name,email,avatar"
|
249 |
async with aiohttp.ClientSession() as session:
|
|
|
254 |
return data[0]
|
255 |
return None
|
256 |
|
257 |
+
# Collect stylist tasks
|
258 |
transfers = []
|
259 |
tasks = []
|
260 |
|
|
|
272 |
|
273 |
status_id = charge["status"]
|
274 |
status_info = status_map.get(status_id, {
|
275 |
+
"label": "Unknown",
|
276 |
+
"color": "#9ca3af"
|
277 |
})
|
278 |
|
279 |
transfers.append({
|
|
|
302 |
except HTTPException as he:
|
303 |
raise he
|
304 |
except Exception as e:
|
305 |
+
logger.error(f"❌ Error retrieving transfers: {str(e)}")
|
306 |
+
raise HTTPException(status_code=500, detail="Internal error while fetching transfer history.")
|