habulaj commited on
Commit
664c52f
·
verified ·
1 Parent(s): c45a0bc

Update routes/stylist.py

Browse files
Files changed (1) hide show
  1. routes/stylist.py +29 -225
routes/stylist.py CHANGED
@@ -29,17 +29,12 @@ logging.basicConfig(level=logging.INFO)
29
  logger = logging.getLogger(__name__)
30
 
31
  def verify_token(user_token: str) -> str:
32
- """
33
- Valida o token JWT no Supabase e retorna o user_id se for válido.
34
- """
35
  headers = {
36
  "Authorization": f"Bearer {user_token}",
37
  "apikey": SUPABASE_KEY,
38
  "Content-Type": "application/json"
39
  }
40
-
41
  response = requests.get(f"{SUPABASE_URL}/auth/v1/user", headers=headers)
42
-
43
  if response.status_code == 200:
44
  user_data = response.json()
45
  user_id = user_data.get("id")
@@ -49,286 +44,95 @@ def verify_token(user_token: str) -> str:
49
  else:
50
  raise HTTPException(status_code=401, detail="Invalid or expired token")
51
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  def get_monthly_revenue(account_id: str) -> List[Dict[str, Any]]:
53
- """
54
- Busca os valores recebidos nos últimos 6 meses para o account_id.
55
- Retorna uma lista com número do mês, nome do mês, indicador se é o mês atual, valor
56
- e porcentagem de crescimento/queda em relação ao mês anterior.
57
- """
58
- # Obter data atual no fuso horário de Nova York
59
  ny_timezone = pytz.timezone('America/New_York')
60
  now_ny = datetime.now(ny_timezone)
61
  current_month = now_ny.month
62
  current_year = now_ny.year
63
-
64
- # Preparar dicionário com os últimos 6 meses (incluindo o atual)
65
  monthly_data = {}
66
-
67
- # Criar entradas para os últimos 6 meses, mesmo sem dados
68
  for i in range(6):
69
- # Calcular o mês e ano para i meses atrás
70
  target_date = now_ny - relativedelta(months=i)
71
  month_num = target_date.month
72
- month_name = target_date.strftime('%b') # Formato abreviado do mês (Jan, Feb, etc)
73
  year = target_date.year
74
-
75
- # Chave composta para garantir unicidade (ano-mês)
76
  month_key = f"{year}-{month_num}"
77
-
78
- # Verificar se é o mês atual
79
  is_current = (month_num == current_month and year == current_year)
80
-
81
- monthly_data[month_key] = {
82
- "month": month_num,
83
- "name": month_name,
84
- "current": is_current,
85
- "amount": 0,
86
- "growth_percentage": None # Será calculado depois
87
- }
88
-
89
- # Calcular o timestamp para 6 meses atrás
90
  start_date = now_ny - relativedelta(months=6)
91
  start_timestamp = int(start_date.timestamp())
92
-
93
- # Buscar transferências para a conta
94
  try:
95
- transfers = stripe.Transfer.list(
96
- destination=account_id,
97
- created={"gte": start_timestamp},
98
- limit=100 # Limitando a 100 transferências mais recentes
99
- )
100
-
101
- # Processar as transferências
102
  for transfer in transfers.data:
103
  transfer_date = datetime.fromtimestamp(transfer.created, ny_timezone)
104
  month_num = transfer_date.month
105
  year = transfer_date.year
106
  month_key = f"{year}-{month_num}"
107
-
108
- # Verificar se o mês está dentro dos últimos 6 meses
109
  if month_key in monthly_data:
110
- # Adicionar o valor da transferência (em centavos)
111
  monthly_data[month_key]["amount"] += transfer.amount
112
-
113
- # Converter para lista e ordenar por data (mais antigo primeiro)
114
  result = list(monthly_data.values())
115
  result.sort(key=lambda x: (current_month - x["month"]) % 12)
116
-
117
- # Calcular a porcentagem de crescimento/queda para cada mês
118
- for i in range(1, len(result)):
119
- current_amount = result[i]["amount"]
120
- previous_amount = result[i-1]["amount"]
121
-
122
- # Lógica corrigida para calcular o crescimento
123
- if previous_amount == 0 and current_amount > 0:
124
- # Se o mês anterior foi zero e o atual tem valor, é crescimento de 100%
125
- result[i]["growth_percentage"] = {
126
- "direction": "up",
127
- "value": 100.0
128
- }
129
- elif previous_amount == 0 and current_amount == 0:
130
- # Se ambos são zero, não há mudança
131
- result[i]["growth_percentage"] = None
132
- elif previous_amount > 0 and current_amount == 0:
133
- # Se o anterior tinha valor e o atual é zero, é queda de 100%
134
- result[i]["growth_percentage"] = {
135
- "direction": "down",
136
- "value": 100.0
137
- }
138
- elif previous_amount > 0:
139
- # Cálculo normal quando ambos têm valores
140
- growth = ((current_amount - previous_amount) / previous_amount) * 100
141
- direction = "up" if growth >= 0 else "down"
142
- result[i]["growth_percentage"] = {
143
- "direction": direction,
144
- "value": round(abs(growth), 1)
145
- }
146
-
147
  return result
148
-
149
  except Exception as e:
150
  logger.error(f"❌ Error getting monthly revenue: {str(e)}")
151
- # Retornar os meses mesmo sem transferências
152
  return list(monthly_data.values())
153
 
154
  def get_account_balance(account_id: str) -> Dict[str, Any]:
155
- """
156
- Busca o saldo disponível e pendente da conta Stripe.
157
- """
158
  try:
159
  balance = stripe.Balance.retrieve(stripe_account=account_id)
160
-
161
- # Inicializar valores
162
  available_balance = 0
163
  pending_balance = 0
164
- currency = "BRL" # Default para BRL
165
-
166
- # Calcular saldo disponível
167
  for balance_item in balance.available:
168
  if balance_item.currency.upper() == "BRL":
169
  available_balance = balance_item.amount
170
- currency = "BRL"
171
  break
172
-
173
- # Calcular saldo pendente
174
  for balance_item in balance.pending:
175
  if balance_item.currency.upper() == "BRL":
176
  pending_balance = balance_item.amount
177
  break
178
-
179
- return {
180
- "available_balance": available_balance,
181
- "pending_balance": pending_balance,
182
- "currency": currency
183
- }
184
-
185
  except Exception as e:
186
  logger.error(f"❌ Error getting account balance: {str(e)}")
187
- return {
188
- "available_balance": 0,
189
- "pending_balance": 0,
190
- "currency": "BRL"
191
- }
192
-
193
- def get_total_followers(user_id: str, user_token: str) -> int:
194
- """
195
- Busca o total de seguidores do usuário na tabela 'followers'.
196
- """
197
- try:
198
- # Consulta para contar os seguidores onde following_id é o user_id
199
- followers_url = f"{SUPABASE_URL}/rest/v1/followers?select=count&following_id=eq.{user_id}"
200
-
201
- response = requests.get(
202
- followers_url,
203
- headers={
204
- "Authorization": f"Bearer {user_token}",
205
- "apikey": SUPABASE_KEY,
206
- "Content-Type": "application/json",
207
- "Prefer": "count=exact"
208
- }
209
- )
210
-
211
- if response.status_code != 200:
212
- logger.error(f"❌ Error getting followers count: Status code {response.status_code}")
213
- return 0
214
-
215
- # Tentar obter o formato de resposta do corpo - formato diferente do esperado
216
- try:
217
- # Se a resposta for um array com um objeto que tem o campo count
218
- response_data = response.json()
219
- if isinstance(response_data, list) and len(response_data) > 0 and "count" in response_data[0]:
220
- return int(response_data[0]["count"])
221
- except Exception as e:
222
- logger.error(f"❌ Error parsing followers count: {str(e)}")
223
-
224
- # Tentar o método anterior como fallback
225
- count = int(response.headers.get("Content-Range", "0-0/0").split("/")[-1])
226
- return count
227
-
228
- except Exception as e:
229
- logger.error(f"❌ Error getting total followers: {str(e)}")
230
- return 0
231
-
232
- def get_total_subscribers(user_id: str, user_token: str) -> int:
233
- """
234
- Busca o total de inscritos ativos do usuário na tabela 'Subscriptions'.
235
- """
236
- try:
237
- # Consulta para contar as inscrições ativas onde stylist_id é o user_id
238
- subscribers_url = f"{SUPABASE_URL}/rest/v1/Subscriptions?select=count&stylist_id=eq.{user_id}&active=eq.true"
239
-
240
- response = requests.get(
241
- subscribers_url,
242
- headers={
243
- "Authorization": f"Bearer {user_token}",
244
- "apikey": SUPABASE_KEY,
245
- "Content-Type": "application/json",
246
- "Prefer": "count=exact"
247
- }
248
- )
249
-
250
- if response.status_code != 200:
251
- logger.error(f"❌ Error getting subscribers count: Status code {response.status_code}")
252
- return 0
253
-
254
- # Tentar obter o formato de resposta do corpo - formato diferente do esperado
255
- try:
256
- # Se a resposta for um array com um objeto que tem o campo count
257
- response_data = response.json()
258
- if isinstance(response_data, list) and len(response_data) > 0 and "count" in response_data[0]:
259
- return int(response_data[0]["count"])
260
- except Exception as e:
261
- logger.error(f"❌ Error parsing subscribers count: {str(e)}")
262
-
263
- # Tentar o método anterior como fallback
264
- count = int(response.headers.get("Content-Range", "0-0/0").split("/")[-1])
265
- return count
266
-
267
- except Exception as e:
268
- logger.error(f"❌ Error getting total subscribers: {str(e)}")
269
- return 0
270
 
271
  @router.get("/dashboard")
272
  def get_dashboard(user_token: str = Header(None, alias="User-key")):
273
  try:
274
  if not user_token:
275
  raise HTTPException(status_code=401, detail="Missing User-key header")
276
-
277
- # Validar o token e obter user_id
278
  user_id = verify_token(user_token)
279
  logger.info(f"🔹 User verified. user_id: {user_id}")
280
-
281
- # Buscar stripe_id do usuário no Supabase
282
  user_data_url = f"{SUPABASE_URL}/rest/v1/User?id=eq.{user_id}"
283
- response = requests.get(
284
- user_data_url,
285
- headers={
286
- "Authorization": f"Bearer {user_token}",
287
- "apikey": SUPABASE_KEY,
288
- "Content-Type": "application/json"
289
- }
290
- )
291
-
292
  if response.status_code != 200 or not response.json():
293
  raise HTTPException(status_code=404, detail="User not found")
294
-
295
  user_data = response.json()[0]
296
  stripe_id = user_data.get("stripe_id")
297
-
298
- # Buscar total de seguidores
299
- total_followers = get_total_followers(user_id, user_token)
300
-
301
- # Buscar total de inscritos ativos
302
- total_subscribers = get_total_subscribers(user_id, user_token)
303
-
304
- # Resposta padrão se não houver stripe_id
305
  if not stripe_id:
306
- return {
307
- "stripe_id": None,
308
- "available_balance": 0,
309
- "pending_balance": 0,
310
- "currency": "BRL",
311
- "monthly_revenue": [],
312
- "total_followers": total_followers,
313
- "total_subscribers": total_subscribers
314
- }
315
-
316
- # Buscar saldo da conta
317
  balance_info = get_account_balance(stripe_id)
318
-
319
- # Buscar valores recebidos nos últimos 6 meses
320
  monthly_revenue = get_monthly_revenue(stripe_id)
321
-
322
- return {
323
- "stripe_id": stripe_id,
324
- "available_balance": balance_info["available_balance"],
325
- "pending_balance": balance_info["pending_balance"],
326
- "currency": balance_info["currency"],
327
- "monthly_revenue": monthly_revenue,
328
- "total_followers": total_followers,
329
- "total_subscribers": total_subscribers
330
- }
331
-
332
  except HTTPException as http_err:
333
  raise http_err
334
  except Exception as e:
 
29
  logger = logging.getLogger(__name__)
30
 
31
  def verify_token(user_token: str) -> str:
 
 
 
32
  headers = {
33
  "Authorization": f"Bearer {user_token}",
34
  "apikey": SUPABASE_KEY,
35
  "Content-Type": "application/json"
36
  }
 
37
  response = requests.get(f"{SUPABASE_URL}/auth/v1/user", headers=headers)
 
38
  if response.status_code == 200:
39
  user_data = response.json()
40
  user_id = user_data.get("id")
 
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 get_monthly_revenue(account_id: str) -> List[Dict[str, Any]]:
 
 
 
 
 
 
66
  ny_timezone = pytz.timezone('America/New_York')
67
  now_ny = datetime.now(ny_timezone)
68
  current_month = now_ny.month
69
  current_year = now_ny.year
 
 
70
  monthly_data = {}
 
 
71
  for i in range(6):
 
72
  target_date = now_ny - relativedelta(months=i)
73
  month_num = target_date.month
74
+ month_name = target_date.strftime('%b')
75
  year = target_date.year
 
 
76
  month_key = f"{year}-{month_num}"
 
 
77
  is_current = (month_num == current_month and year == current_year)
78
+ monthly_data[month_key] = {"month": month_num, "name": month_name, "current": is_current, "amount": 0}
 
 
 
 
 
 
 
 
 
79
  start_date = now_ny - relativedelta(months=6)
80
  start_timestamp = int(start_date.timestamp())
 
 
81
  try:
82
+ transfers = stripe.Transfer.list(destination=account_id, created={"gte": start_timestamp}, limit=100)
 
 
 
 
 
 
83
  for transfer in transfers.data:
84
  transfer_date = datetime.fromtimestamp(transfer.created, ny_timezone)
85
  month_num = transfer_date.month
86
  year = transfer_date.year
87
  month_key = f"{year}-{month_num}"
 
 
88
  if month_key in monthly_data:
 
89
  monthly_data[month_key]["amount"] += transfer.amount
 
 
90
  result = list(monthly_data.values())
91
  result.sort(key=lambda x: (current_month - x["month"]) % 12)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  return result
 
93
  except Exception as e:
94
  logger.error(f"❌ Error getting monthly revenue: {str(e)}")
 
95
  return list(monthly_data.values())
96
 
97
  def get_account_balance(account_id: str) -> Dict[str, Any]:
 
 
 
98
  try:
99
  balance = stripe.Balance.retrieve(stripe_account=account_id)
 
 
100
  available_balance = 0
101
  pending_balance = 0
102
+ currency = "BRL"
 
 
103
  for balance_item in balance.available:
104
  if balance_item.currency.upper() == "BRL":
105
  available_balance = balance_item.amount
 
106
  break
 
 
107
  for balance_item in balance.pending:
108
  if balance_item.currency.upper() == "BRL":
109
  pending_balance = balance_item.amount
110
  break
111
+ return {"available_balance": available_balance, "pending_balance": pending_balance, "currency": currency}
 
 
 
 
 
 
112
  except Exception as e:
113
  logger.error(f"❌ Error getting account balance: {str(e)}")
114
+ return {"available_balance": 0, "pending_balance": 0, "currency": "BRL"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
 
116
  @router.get("/dashboard")
117
  def get_dashboard(user_token: str = Header(None, alias="User-key")):
118
  try:
119
  if not user_token:
120
  raise HTTPException(status_code=401, detail="Missing User-key header")
 
 
121
  user_id = verify_token(user_token)
122
  logger.info(f"🔹 User verified. user_id: {user_id}")
 
 
123
  user_data_url = f"{SUPABASE_URL}/rest/v1/User?id=eq.{user_id}"
124
+ response = requests.get(user_data_url, headers={"Authorization": f"Bearer {user_token}", "apikey": SUPABASE_KEY, "Content-Type": "application/json"})
 
 
 
 
 
 
 
 
125
  if response.status_code != 200 or not response.json():
126
  raise HTTPException(status_code=404, detail="User not found")
 
127
  user_data = response.json()[0]
128
  stripe_id = user_data.get("stripe_id")
129
+ total_followers = get_total_followers(user_id)
130
+ total_subscribers = get_total_subscribers(user_id)
 
 
 
 
 
 
131
  if not stripe_id:
132
+ return {"stripe_id": None, "available_balance": 0, "pending_balance": 0, "currency": "BRL", "monthly_revenue": [], "total_followers": total_followers, "total_subscribers": total_subscribers}
 
 
 
 
 
 
 
 
 
 
133
  balance_info = get_account_balance(stripe_id)
 
 
134
  monthly_revenue = get_monthly_revenue(stripe_id)
135
+ return {"stripe_id": stripe_id, "available_balance": balance_info["available_balance"], "pending_balance": balance_info["pending_balance"], "currency": balance_info["currency"], "monthly_revenue": monthly_revenue, "total_followers": total_followers, "total_subscribers": total_subscribers}
 
 
 
 
 
 
 
 
 
 
136
  except HTTPException as http_err:
137
  raise http_err
138
  except Exception as e: