brestok commited on
Commit
72464e7
·
1 Parent(s): 6e16863

Refactor account and call management features

Browse files

- Removed the discount code router and related functionality from the project.
- Introduced `update_account_status_obj` function to handle account status updates.
- Added `ChangeStatusRequest` schema for updating account status via API.
- Updated account model to include a phone number field instead of picture URL.
- Cleaned up unused reschedule call functionality and related schemas.
- Enhanced account creation process to include phone number and account status.

cbh/api/calls/db_requests.py CHANGED
@@ -25,23 +25,14 @@ async def create_call_obj(
25
  event: EventModel,
26
  coach: AccountShorten,
27
  customer: AccountModel,
28
- is_business: bool,
29
  ) -> CallModel:
30
  """
31
  Create a new call.
32
  """
33
- from cbh.api.calls.services.daily import create_meeting_room
34
-
35
- status = CallStatus.SCHEDULED if is_business else CallStatus.CREATED
36
- room_url = None
37
- if is_business:
38
- room_url = await create_meeting_room(event)
39
  call = CallModel(
40
  event=EventShorten(**event.model_dump()),
41
  customer=AccountShorten(**customer.model_dump()),
42
  coach=coach,
43
- status=status,
44
- roomUrl=room_url,
45
  )
46
  await settings.DB_CLIENT.calls.insert_one(call.to_mongo())
47
  return call
@@ -155,12 +146,6 @@ async def filter_calls_objs(
155
  return calls, total_count
156
 
157
 
158
- async def verify_discount_code(discount_code: str | None) -> bool:
159
- """
160
- Verify discount code.
161
- """
162
- return True
163
-
164
  def _generate_time_slots(start: datetime, end: datetime) -> list[datetime]:
165
  """
166
  Generate time slots between start and end.
@@ -182,7 +167,7 @@ def _generate_time_slots(start: datetime, end: datetime) -> list[datetime]:
182
  async def calculate_call_availabilities(
183
  startDate: datetime,
184
  endDate: datetime,
185
- isBusiness: bool,
186
  ) -> CallAvailabilityResponse:
187
  """
188
  Get call availabilities.
@@ -194,7 +179,7 @@ async def calculate_call_availabilities(
194
 
195
  opportunity_filter = (
196
  [CoachOpportunity.BUSINESS.value, CoachOpportunity.BOTH.value]
197
- if isBusiness
198
  else [CoachOpportunity.GENERAL.value, CoachOpportunity.BOTH.value]
199
  )
200
 
@@ -370,9 +355,3 @@ async def check_call_payment(call_id: str) -> StripeCheckResponse:
370
  is_processed = True if call["status"] == CallStatus.SCHEDULED.value else False
371
  success = call["event"]["isActive"]
372
  return StripeCheckResponse(isProcessed=is_processed, success=success)
373
-
374
-
375
- if __name__ == "__main__":
376
- import asyncio
377
-
378
- asyncio.run(verify_discount_code("TEST_CODE"))
 
25
  event: EventModel,
26
  coach: AccountShorten,
27
  customer: AccountModel,
 
28
  ) -> CallModel:
29
  """
30
  Create a new call.
31
  """
 
 
 
 
 
 
32
  call = CallModel(
33
  event=EventShorten(**event.model_dump()),
34
  customer=AccountShorten(**customer.model_dump()),
35
  coach=coach,
 
 
36
  )
37
  await settings.DB_CLIENT.calls.insert_one(call.to_mongo())
38
  return call
 
146
  return calls, total_count
147
 
148
 
 
 
 
 
 
 
149
  def _generate_time_slots(start: datetime, end: datetime) -> list[datetime]:
150
  """
151
  Generate time slots between start and end.
 
167
  async def calculate_call_availabilities(
168
  startDate: datetime,
169
  endDate: datetime,
170
+ promotion_code: str | None,
171
  ) -> CallAvailabilityResponse:
172
  """
173
  Get call availabilities.
 
179
 
180
  opportunity_filter = (
181
  [CoachOpportunity.BUSINESS.value, CoachOpportunity.BOTH.value]
182
+ if promotion_code
183
  else [CoachOpportunity.GENERAL.value, CoachOpportunity.BOTH.value]
184
  )
185
 
 
355
  is_processed = True if call["status"] == CallStatus.SCHEDULED.value else False
356
  success = call["event"]["isActive"]
357
  return StripeCheckResponse(isProcessed=is_processed, success=success)
 
 
 
 
 
 
cbh/api/calls/services/__init__.py CHANGED
@@ -3,10 +3,12 @@ from .stripe import (
3
  verify_stripe_webhook,
4
  manage_stripe_event,
5
  refund_stripe_payment,
 
6
  )
7
  __all__ = [
8
  "create_stripe_session",
9
  "verify_stripe_webhook",
10
  "manage_stripe_event",
11
  "refund_stripe_payment",
 
12
  ]
 
3
  verify_stripe_webhook,
4
  manage_stripe_event,
5
  refund_stripe_payment,
6
+ verify_discount_code,
7
  )
8
  __all__ = [
9
  "create_stripe_session",
10
  "verify_stripe_webhook",
11
  "manage_stripe_event",
12
  "refund_stripe_payment",
13
+ "verify_discount_code",
14
  ]
cbh/api/calls/services/stripe.py CHANGED
@@ -11,7 +11,7 @@ from cbh.api.common.db_requests import get_obj_by_id
11
  from cbh.core.config import settings
12
 
13
 
14
- async def create_stripe_session(call: CallModel) -> str:
15
  """
16
  Create a stripe session.
17
  """
@@ -19,13 +19,13 @@ async def create_stripe_session(call: CallModel) -> str:
19
  "callId": call.id,
20
  }
21
 
22
- checkout_session = await settings.STRIPE_CLIENT.checkout.sessions.create_async(
23
  params={
24
  "customer_email": call.customer.email,
25
  "line_items": [
26
  {
27
  "price_data": {
28
- "currency": "usd",
29
  "unit_amount": 150 * 100,
30
  "product_data": {
31
  "name": "Coaching Session",
@@ -39,6 +39,7 @@ async def create_stripe_session(call: CallModel) -> str:
39
  "success_url": f"{settings.Audience}/payment/success?callId={call.id}",
40
  "cancel_url": f"{settings.Audience}/payment/cancel?callId={call.id}",
41
  "metadata": metadata,
 
42
  "expires_at": int(time.time()) + 1800,
43
  },
44
  options={"api_key": settings.STRIPE_API_KEY},
@@ -67,16 +68,16 @@ async def manage_stripe_event(event: dict) -> str:
67
 
68
  call_id = pydash.get(session, "metadata.callId")
69
  call = await get_obj_by_id(CallModel, call_id)
70
- print(f'Event type: {event_type}')
71
- print(f'Session: {session}')
72
  if event_type in [
73
  "checkout.session.completed",
74
  "checkout.session.async_payment_succeeded",
75
  ]:
76
  payment_intent_id = session.get("payment_intent")
77
- print(f'Payment intent id: {payment_intent_id}')
78
  meeting_room = await create_meeting_room(call.event)
79
- print(f'Meeting room: {meeting_room}')
80
  await enable_call(call, payment_intent_id, meeting_room)
81
 
82
  elif event_type in (
@@ -91,10 +92,24 @@ async def refund_stripe_payment(payment_intent_id: str) -> None:
91
  Refund a Stripe payment.
92
  """
93
  try:
94
- await settings.STRIPE_CLIENT.refunds.create_async(
95
  payment_intent=payment_intent_id,
96
  )
97
  except stripe.error.StripeError as e:
98
  raise HTTPException(
99
  status_code=400, detail=f"Failed to refund payment: {str(e)}"
100
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  from cbh.core.config import settings
12
 
13
 
14
+ async def create_stripe_session(call: CallModel, code: str | None) -> str:
15
  """
16
  Create a stripe session.
17
  """
 
19
  "callId": call.id,
20
  }
21
 
22
+ checkout_session = await settings.STRIPE_CLIENT.v1.checkout.sessions.create_async(
23
  params={
24
  "customer_email": call.customer.email,
25
  "line_items": [
26
  {
27
  "price_data": {
28
+ "currency": "eur",
29
  "unit_amount": 150 * 100,
30
  "product_data": {
31
  "name": "Coaching Session",
 
39
  "success_url": f"{settings.Audience}/payment/success?callId={call.id}",
40
  "cancel_url": f"{settings.Audience}/payment/cancel?callId={call.id}",
41
  "metadata": metadata,
42
+ "discounts": [{"promotion_code": code}] if code else None,
43
  "expires_at": int(time.time()) + 1800,
44
  },
45
  options={"api_key": settings.STRIPE_API_KEY},
 
68
 
69
  call_id = pydash.get(session, "metadata.callId")
70
  call = await get_obj_by_id(CallModel, call_id)
71
+ print(f"Event type: {event_type}")
72
+ print(f"Session: {session}")
73
  if event_type in [
74
  "checkout.session.completed",
75
  "checkout.session.async_payment_succeeded",
76
  ]:
77
  payment_intent_id = session.get("payment_intent")
78
+ print(f"Payment intent id: {payment_intent_id}")
79
  meeting_room = await create_meeting_room(call.event)
80
+ print(f"Meeting room: {meeting_room}")
81
  await enable_call(call, payment_intent_id, meeting_room)
82
 
83
  elif event_type in (
 
92
  Refund a Stripe payment.
93
  """
94
  try:
95
+ await settings.STRIPE_CLIENT.v1.refunds.create_async(
96
  payment_intent=payment_intent_id,
97
  )
98
  except stripe.error.StripeError as e:
99
  raise HTTPException(
100
  status_code=400, detail=f"Failed to refund payment: {str(e)}"
101
  )
102
+
103
+
104
+ async def verify_discount_code(discount_code: str | None) -> str | None:
105
+ """
106
+ Verify discount code.
107
+ """
108
+ if not discount_code:
109
+ return None
110
+ promotion_codes = await settings.STRIPE_CLIENT.v1.promotion_codes.list_async(
111
+ params={"code": discount_code, "active": True}
112
+ )
113
+ if not promotion_codes.data:
114
+ raise HTTPException(status_code=400, detail="Invalid discount code")
115
+ return promotion_codes.data[0].id
cbh/api/calls/views.py CHANGED
@@ -13,7 +13,6 @@ from cbh.api.calls.db_requests import (
13
  create_call_obj,
14
  create_event_obj,
15
  filter_calls_objs,
16
- verify_discount_code,
17
  )
18
  from cbh.api.calls.models import CallModel
19
  from cbh.api.calls.schemas import (
@@ -29,6 +28,7 @@ from cbh.api.calls.services import (
29
  manage_stripe_event,
30
  refund_stripe_payment,
31
  verify_stripe_webhook,
 
32
  )
33
  from cbh.api.calls.services.daily import create_daily_token
34
  from cbh.api.calls.utils import can_edit_call
@@ -70,8 +70,8 @@ async def get_availabilities(
70
  """
71
  Get availabilities.
72
  """
73
- is_business = await verify_discount_code(discountCode)
74
- response = await calculate_call_availabilities(startDate, endDate, is_business)
75
  return CbhResponseWrapper(data=response)
76
 
77
 
@@ -114,18 +114,15 @@ async def purchase_call(
114
  """
115
  Purchase a call.
116
  """
117
- coach, is_business = await asyncio.gather(
118
  get_obj_by_id(
119
  AccountShorten, request.coachId, projection=AccountShorten.to_mongo_fields()
120
  ),
121
  verify_discount_code(request.discountCode),
122
  )
123
  event = await create_event_obj(request, coach)
124
- call = await create_call_obj(event, coach, account, is_business)
125
-
126
- session_url = None
127
- if not is_business:
128
- session_url = await create_stripe_session(call)
129
  return CbhResponseWrapper(data=StripeSessionResponse(sessionUrl=session_url))
130
 
131
 
 
13
  create_call_obj,
14
  create_event_obj,
15
  filter_calls_objs,
 
16
  )
17
  from cbh.api.calls.models import CallModel
18
  from cbh.api.calls.schemas import (
 
28
  manage_stripe_event,
29
  refund_stripe_payment,
30
  verify_stripe_webhook,
31
+ verify_discount_code,
32
  )
33
  from cbh.api.calls.services.daily import create_daily_token
34
  from cbh.api.calls.utils import can_edit_call
 
70
  """
71
  Get availabilities.
72
  """
73
+ promotion_code = await verify_discount_code(discountCode)
74
+ response = await calculate_call_availabilities(startDate, endDate, promotion_code)
75
  return CbhResponseWrapper(data=response)
76
 
77
 
 
114
  """
115
  Purchase a call.
116
  """
117
+ coach, promotion_code = await asyncio.gather(
118
  get_obj_by_id(
119
  AccountShorten, request.coachId, projection=AccountShorten.to_mongo_fields()
120
  ),
121
  verify_discount_code(request.discountCode),
122
  )
123
  event = await create_event_obj(request, coach)
124
+ call = await create_call_obj(event, coach, account)
125
+ session_url = await create_stripe_session(call, promotion_code)
 
 
 
126
  return CbhResponseWrapper(data=StripeSessionResponse(sessionUrl=session_url))
127
 
128