victoria-latynina commited on
Commit
7ef6e86
·
verified ·
1 Parent(s): 1da7845

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +62 -34
app.py CHANGED
@@ -46,39 +46,57 @@ class MindbodyClient:
46
  resp.raise_for_status()
47
  return resp.json()
48
 
49
- # --------------------------- public endpoints --------------------------
50
- def get_class_descriptions(self, location_id: str | int):
51
- """Return **types of training** offered at a location."""
52
- params = {"LocationIds": location_id}
53
  return self._get("/class/classdescriptions", params)
54
 
55
- def get_classes(self, location_id: str | int, start_iso: str, end_iso: str):
56
- """Return **scheduled classes** for a date range."""
57
- params = {
58
- "LocationIds": location_id,
59
- "StartDateTime": start_iso,
60
- "EndDateTime": end_iso,
61
- }
 
 
 
 
 
 
 
 
 
 
 
62
  return self._get("/class/classes", params)
63
 
64
- def book_class(self, class_id: int, client_id: str, cross_regional: bool = False):
 
 
 
 
 
 
 
 
65
  """Book a client into a class *after* verifying availability."""
66
- # 1) confirm availability
67
- info = self._get("/class/classes", {"ClassIds": class_id})
68
- if not info.get("Classes"):
69
- raise ValueError("Class ID not found")
70
-
71
- cls = info["Classes"][0]
72
  if not cls.get("IsAvailable", False):
73
- raise ValueError("Class is not available for online booking")
74
  if cls.get("TotalBooked", 0) >= cls.get("MaxCapacity", 0):
75
  raise ValueError("Class is already full")
76
 
77
- # 2) book
78
  payload = {
79
  "ClientId": client_id,
80
  "ClassId": class_id,
81
  "CrossRegionalBooking": cross_regional,
 
 
82
  }
83
  return self._post("/class/addclienttoclass", payload)
84
 
@@ -129,43 +147,53 @@ def get_training_types(location_id: str | int):
129
  return f"❌ Error: {exc}"
130
 
131
 
132
- def get_schedule(location_id: str | int, days: int):
133
  """Return upcoming classes in a human-friendly Markdown list."""
134
  if not mb_client:
135
  return "❌ Authenticate first."
136
 
137
  try:
138
- start_iso = datetime.now().strftime("%Y-%m-%dT00:00:00")
139
- end_iso = (datetime.now() + timedelta(days=int(days))).strftime("%Y-%m-%dT23:59:59")
140
- res = mb_client.get_classes(location_id, start_iso, end_iso)
 
 
 
 
 
 
141
  classes = res.get("Classes", [])
142
  if not classes:
143
  return "⚠️ No classes in the selected window."
144
 
145
- formatted = []
146
  for c in classes:
147
- dt = c.get("StartDateTime", "?")
148
- name = c.get("ClassDescription", {}).get("Name", "🆔" + str(c.get("ClassDescriptionId")))
149
- ok = "✅" if c.get("IsAvailable") else "❌"
150
- cid = c.get("Id")
151
- formatted.append(f"{dt} | {name} | {ok} | ClassId: {cid}")
152
 
153
- return "📅 Schedule\n" + "\n".join(formatted)
154
  except Exception as exc:
155
  logger.exception("Error while fetching schedule")
156
  return f"❌ Error: {exc}"
157
 
158
 
159
  def book_class_gr(class_id: int, client_id: str, cross_regional: bool):
160
- """Book a class through the UI."""
161
  if not mb_client:
162
  return "❌ Authenticate first."
163
 
164
  try:
165
- res = mb_client.book_class(class_id, client_id, cross_regional)
 
 
 
 
166
  visit = res.get("Visit", {})
167
  status = visit.get("AppointmentStatus", "OK")
168
- return f"🎉 Booked! Status: {status}\n\nFull response:\n{res}"
 
169
  except Exception as exc:
170
  logger.exception("Booking failed")
171
  return f"❌ Could not book: {exc}"
 
46
  resp.raise_for_status()
47
  return resp.json()
48
 
49
+ def get_class_descriptions(self, location_id: int | str):
50
+ params = {"locationIds": location_id}
 
 
51
  return self._get("/class/classdescriptions", params)
52
 
53
+ def get_classes(
54
+ self,
55
+ *,
56
+ location_id: int | str | None = None,
57
+ start_iso: str | None = None,
58
+ end_iso: str | None = None,
59
+ class_ids: list[int] | None = None,
60
+ ):
61
+ """Return scheduled classes. Accepts *either* a location or explicit classIds."""
62
+ params: dict[str, str | list[int]] = {}
63
+ if location_id is not None:
64
+ params["locationIds"] = location_id
65
+ if class_ids:
66
+ params["classIds"] = class_ids
67
+ if start_iso:
68
+ params["startDateTime"] = start_iso
69
+ if end_iso:
70
+ params["endDateTime"] = end_iso
71
  return self._get("/class/classes", params)
72
 
73
+ def book_class(
74
+ self,
75
+ *,
76
+ class_id: int,
77
+ client_id: str,
78
+ cross_regional: bool = False,
79
+ require_payment: bool = False,
80
+ send_email: bool = False,
81
+ ):
82
  """Book a client into a class *after* verifying availability."""
83
+ # 1) quick availability check
84
+ info = self.get_classes(class_ids=[class_id])
85
+ cls = (info.get("Classes") or [None])[0]
86
+ if not cls:
87
+ raise ValueError(f"Class {class_id} not found")
 
88
  if not cls.get("IsAvailable", False):
89
+ raise ValueError("Class is not open for online booking")
90
  if cls.get("TotalBooked", 0) >= cls.get("MaxCapacity", 0):
91
  raise ValueError("Class is already full")
92
 
93
+ # 2) book it
94
  payload = {
95
  "ClientId": client_id,
96
  "ClassId": class_id,
97
  "CrossRegionalBooking": cross_regional,
98
+ "RequirePayment": require_payment,
99
+ "SendEmail": send_email,
100
  }
101
  return self._post("/class/addclienttoclass", payload)
102
 
 
147
  return f"❌ Error: {exc}"
148
 
149
 
150
+ def get_schedule(location_id: str | int, days: float):
151
  """Return upcoming classes in a human-friendly Markdown list."""
152
  if not mb_client:
153
  return "❌ Authenticate first."
154
 
155
  try:
156
+ now = datetime.utcnow()
157
+ start_iso = now.replace(hour=0, minute=0, second=0, microsecond=0).isoformat()
158
+ end_iso = (now + timedelta(days=int(days))).replace(
159
+ hour=23, minute=59, second=59, microsecond=0
160
+ ).isoformat()
161
+
162
+ res = mb_client.get_classes(
163
+ location_id=location_id, start_iso=start_iso, end_iso=end_iso
164
+ )
165
  classes = res.get("Classes", [])
166
  if not classes:
167
  return "⚠️ No classes in the selected window."
168
 
169
+ lines: list[str] = []
170
  for c in classes:
171
+ when = c["StartDateTime"][:16].replace("T", " ") # YYYY-MM-DD HH:MM
172
+ name = c.get("ClassDescription", {}).get("Name") or f"ID {c['ClassDescriptionId']}"
173
+ ok = "✅" if c["IsAvailable"] else "❌"
174
+ cid = c["Id"]
175
+ lines.append(f"{when} | {name} | {ok} | ClassId: {cid}")
176
 
177
+ return "### 📅 Schedule\n" + "\n".join(lines)
178
  except Exception as exc:
179
  logger.exception("Error while fetching schedule")
180
  return f"❌ Error: {exc}"
181
 
182
 
183
  def book_class_gr(class_id: int, client_id: str, cross_regional: bool):
 
184
  if not mb_client:
185
  return "❌ Authenticate first."
186
 
187
  try:
188
+ res = mb_client.book_class(
189
+ class_id=class_id,
190
+ client_id=client_id,
191
+ cross_regional=cross_regional,
192
+ )
193
  visit = res.get("Visit", {})
194
  status = visit.get("AppointmentStatus", "OK")
195
+ readable = visit.get("StartDateTime", "")[:16].replace("T", " ")
196
+ return f"🎉 **Booked {readable} – status {status}**\n\n```json\n{res}\n```"
197
  except Exception as exc:
198
  logger.exception("Booking failed")
199
  return f"❌ Could not book: {exc}"