habulaj commited on
Commit
305e55d
·
verified ·
1 Parent(s): 457fba8

Update routes/subscription.py

Browse files
Files changed (1) hide show
  1. routes/subscription.py +67 -38
routes/subscription.py CHANGED
@@ -60,6 +60,48 @@ class CreatePriceRequest(BaseModel):
60
  emergency_price: int # Valor de emergência (ex: 500 para R$5,00)
61
  consultations: int # Número de consultas (ex: 3)
62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  def get_subscription_from_db(subscription_id: str):
64
  """
65
  Busca a assinatura na tabela 'Subscriptions' com base no subscription_id.
@@ -837,35 +879,33 @@ async def create_price(data: CreatePriceRequest, user_token: str = Header(None,
837
  if not user_token:
838
  raise HTTPException(status_code=401, detail="Missing User-key header")
839
 
 
840
  user_id = verify_token(user_token)
841
  logger.info(f"🔹 User verified. user_id: {user_id}")
842
 
843
  amount = data.amount
844
  emergency_price = data.emergency_price
845
- consultations = data.consultations
846
 
847
  if not (500 <= amount <= 99900):
848
  raise HTTPException(status_code=400, detail="Amount must be between $5 and $999")
849
  if not (500 <= emergency_price <= 99900):
850
  raise HTTPException(status_code=400, detail="Emergency price must be between $5 and $999")
 
 
851
 
852
- if consultations is None:
853
- consultations = 0
854
- elif consultations < 0:
855
- raise HTTPException(status_code=400, detail="Consultations must be greater than or equal to 0")
856
-
857
- logger.info(f"🔹 Validated amounts: amount = {amount}, emergency_price = {emergency_price}, consultations = {consultations}")
858
 
 
859
  supabase_url = f"{SUPABASE_URL}/rest/v1/User?id=eq.{user_id}"
860
  headers = {
861
  "Authorization": f"Bearer {user_token}",
862
  **SUPABASE_HEADERS
863
  }
864
  response = requests.get(supabase_url, headers=headers)
865
- logger.info(f"🔹 Supabase GET response: {response.status_code} - {response.text}")
866
 
867
  if response.status_code != 200:
868
- raise HTTPException(status_code=500, detail=f"Failed to fetch user from Supabase: {response.text}")
869
 
870
  user_data = response.json()
871
  if not user_data:
@@ -873,28 +913,21 @@ async def create_price(data: CreatePriceRequest, user_token: str = Header(None,
873
 
874
  user = user_data[0]
875
  existing_price_id = user.get("price_id")
876
- user_full_name = user.get("name", "Unknown User")
877
- user_avatar = user.get("avatar", None)
878
 
879
  name_parts = user_full_name.split()
880
- if len(name_parts) > 1:
881
- abbreviated_name = f"{name_parts[0]} {name_parts[1][0]}."
882
- else:
883
- abbreviated_name = name_parts[0]
884
-
885
  product_name = f"{abbreviated_name} Subscription"
886
- logger.info(f"🔹 Existing price_id: {existing_price_id}, user_name: {abbreviated_name}")
887
 
888
- product_data = {
889
- "name": product_name,
890
- }
891
 
 
892
  if user_avatar:
893
  product_data["images"] = [user_avatar]
894
 
895
  product = stripe.Product.create(**product_data)
896
  product_id = product.id
897
- logger.info(f"✅ New product created: {product_id}")
898
 
899
  price = stripe.Price.create(
900
  unit_amount=amount,
@@ -903,19 +936,14 @@ async def create_price(data: CreatePriceRequest, user_token: str = Header(None,
903
  product=product_id
904
  )
905
  new_price_id = price.id
906
- logger.info(f"✅ New price created: {new_price_id}")
907
 
908
- # Coletar e logar todos os clientes com assinatura ativa do preço antigo
909
- affected_customers = []
910
 
911
  if existing_price_id:
912
  subscriptions = stripe.Subscription.list(status="active")
913
  for sub in subscriptions.auto_paging_iter():
914
  if sub["items"]["data"][0]["price"]["id"] == existing_price_id:
915
- customer_id = sub["customer"]
916
- affected_customers.append(customer_id)
917
-
918
- # Cancelar no final do período e atualizar para novo preço
919
  stripe.Subscription.modify(sub.id, cancel_at_period_end=True)
920
  stripe.Subscription.modify(
921
  sub.id,
@@ -925,10 +953,11 @@ async def create_price(data: CreatePriceRequest, user_token: str = Header(None,
925
  }],
926
  proration_behavior="none"
927
  )
928
- logger.info(f"🔹 Subscription {sub.id} updated with new price {new_price_id} (customer: {customer_id})")
929
-
930
- logger.info(f"📢 Affected customer IDs with old price: {affected_customers}")
931
 
 
932
  update_data = {
933
  "price_id": new_price_id,
934
  "price": amount,
@@ -945,14 +974,14 @@ async def create_price(data: CreatePriceRequest, user_token: str = Header(None,
945
  update_response = requests.patch(supabase_url, headers=update_headers, json=update_data)
946
 
947
  if update_response.status_code not in [200, 204]:
948
- raise HTTPException(status_code=500, detail=f"Failed to update Supabase: {update_response.text}")
949
 
950
- logger.info(f"✅ Successfully updated user {user_id} with new price_id and prices")
951
- return {
952
- "message": "Price created and user updated successfully!",
953
- "price_id": new_price_id,
954
- "affected_customers": affected_customers
955
- }
956
 
957
  except Exception as e:
958
  logger.error(f"❌ Error creating price: {e}")
 
60
  emergency_price: int # Valor de emergência (ex: 500 para R$5,00)
61
  consultations: int # Número de consultas (ex: 3)
62
 
63
+ def get_active_subscribers_by_price_id(price_id: str) -> list:
64
+ """
65
+ Retorna uma lista de user_ids que têm uma assinatura ativa com o price_id fornecido.
66
+ """
67
+ response = requests.get(
68
+ f"{SUPABASE_URL}/rest/v1/Subscriptions?price_id=eq.{price_id}&select=user_id",
69
+ headers=SUPABASE_ROLE_HEADERS
70
+ )
71
+ if response.status_code == 200:
72
+ data = response.json()
73
+ return [entry["user_id"] for entry in data if "user_id" in entry]
74
+ logger.warning(f"⚠️ Failed to fetch subscribers: {response.status_code} - {response.text}")
75
+ return []
76
+
77
+ def create_notifications_for_price_change(user_ids: list, stylist_id: str):
78
+ """
79
+ Cria registros de notificações na tabela 'Notifications' para todos os usuários afetados.
80
+ """
81
+ if not user_ids:
82
+ return
83
+
84
+ now = datetime.now(pytz.timezone("America/Sao_Paulo")).isoformat()
85
+ payload = [{
86
+ "type": "changeprice",
87
+ "target_user": uid,
88
+ "created_at": now,
89
+ "user_reference": stylist_id,
90
+ "read": False,
91
+ "post_reference": None
92
+ } for uid in user_ids]
93
+
94
+ response = requests.post(
95
+ f"{SUPABASE_URL}/rest/v1/Notifications",
96
+ headers=SUPABASE_ROLE_HEADERS,
97
+ json=payload
98
+ )
99
+
100
+ if response.status_code not in [200, 201]:
101
+ logger.warning(f"⚠️ Failed to create notifications: {response.status_code} - {response.text}")
102
+ else:
103
+ logger.info(f"✅ Created {len(payload)} notifications for affected users.")
104
+
105
  def get_subscription_from_db(subscription_id: str):
106
  """
107
  Busca a assinatura na tabela 'Subscriptions' com base no subscription_id.
 
879
  if not user_token:
880
  raise HTTPException(status_code=401, detail="Missing User-key header")
881
 
882
+ # 1. Validar o token e obter user_id
883
  user_id = verify_token(user_token)
884
  logger.info(f"🔹 User verified. user_id: {user_id}")
885
 
886
  amount = data.amount
887
  emergency_price = data.emergency_price
888
+ consultations = data.consultations or 0
889
 
890
  if not (500 <= amount <= 99900):
891
  raise HTTPException(status_code=400, detail="Amount must be between $5 and $999")
892
  if not (500 <= emergency_price <= 99900):
893
  raise HTTPException(status_code=400, detail="Emergency price must be between $5 and $999")
894
+ if consultations < 0:
895
+ raise HTTPException(status_code=400, detail="Consultations must be >= 0")
896
 
897
+ logger.info(f"🔹 Validated inputs")
 
 
 
 
 
898
 
899
+ # 4. Buscar dados do usuário
900
  supabase_url = f"{SUPABASE_URL}/rest/v1/User?id=eq.{user_id}"
901
  headers = {
902
  "Authorization": f"Bearer {user_token}",
903
  **SUPABASE_HEADERS
904
  }
905
  response = requests.get(supabase_url, headers=headers)
 
906
 
907
  if response.status_code != 200:
908
+ raise HTTPException(status_code=500, detail=f"Failed to fetch user: {response.text}")
909
 
910
  user_data = response.json()
911
  if not user_data:
 
913
 
914
  user = user_data[0]
915
  existing_price_id = user.get("price_id")
916
+ user_full_name = user.get("name", "Unknown")
917
+ user_avatar = user.get("avatar")
918
 
919
  name_parts = user_full_name.split()
920
+ abbreviated_name = f"{name_parts[0]} {name_parts[1][0]}." if len(name_parts) > 1 else name_parts[0]
 
 
 
 
921
  product_name = f"{abbreviated_name} Subscription"
 
922
 
923
+ logger.info(f"🔹 Creating Stripe product")
 
 
924
 
925
+ product_data = {"name": product_name}
926
  if user_avatar:
927
  product_data["images"] = [user_avatar]
928
 
929
  product = stripe.Product.create(**product_data)
930
  product_id = product.id
 
931
 
932
  price = stripe.Price.create(
933
  unit_amount=amount,
 
936
  product=product_id
937
  )
938
  new_price_id = price.id
939
+ logger.info(f"✅ Stripe product and price created: {new_price_id}")
940
 
941
+ affected_users = []
 
942
 
943
  if existing_price_id:
944
  subscriptions = stripe.Subscription.list(status="active")
945
  for sub in subscriptions.auto_paging_iter():
946
  if sub["items"]["data"][0]["price"]["id"] == existing_price_id:
 
 
 
 
947
  stripe.Subscription.modify(sub.id, cancel_at_period_end=True)
948
  stripe.Subscription.modify(
949
  sub.id,
 
953
  }],
954
  proration_behavior="none"
955
  )
956
+ # 🔥 Buscar todos os usuários afetados no Supabase
957
+ affected_users = get_active_subscribers_by_price_id(existing_price_id)
958
+ logger.info(f"🔹 Found {len(affected_users)} affected users.")
959
 
960
+ # Atualiza o usuário no Supabase
961
  update_data = {
962
  "price_id": new_price_id,
963
  "price": amount,
 
974
  update_response = requests.patch(supabase_url, headers=update_headers, json=update_data)
975
 
976
  if update_response.status_code not in [200, 204]:
977
+ raise HTTPException(status_code=500, detail=f"Failed to update user: {update_response.text}")
978
 
979
+ # 🔥 Cria notificações para os afetados
980
+ create_notifications_for_price_change(affected_users, stylist_id=user_id)
981
+
982
+ logger.info(f"✅ User updated and notifications sent")
983
+
984
+ return {"message": "Price created and user updated successfully!", "price_id": new_price_id}
985
 
986
  except Exception as e:
987
  logger.error(f"❌ Error creating price: {e}")