This commit is contained in:
2026-02-16 13:16:18 -06:00
parent d262d80199
commit f140f8f75c
2 changed files with 274 additions and 210 deletions

View File

@@ -39,10 +39,7 @@ _JSON_COLS = {"times", "days_of_week"}
def _wrap_json(data): def _wrap_json(data):
"""Wrap list/dict values in Json() for psycopg2 when targeting JSON columns.""" """Wrap list/dict values in Json() for psycopg2 when targeting JSON columns."""
return { return {k: Json(v) if k in _JSON_COLS and isinstance(v, (list, dict)) else v for k, v in data.items()}
k: Json(v) if k in _JSON_COLS and isinstance(v, (list, dict)) else v
for k, v in data.items()
}
def _filter_times_in_range(times, start, end): def _filter_times_in_range(times, start, end):
@@ -64,84 +61,13 @@ def _is_med_due_today(med, today, current_day):
start = med.get("start_date") start = med.get("start_date")
interval = med.get("interval_days") interval = med.get("interval_days")
if start and interval: if start and interval:
start_d = ( start_d = start if isinstance(start, date) else datetime.strptime(str(start), "%Y-%m-%d").date()
start
if isinstance(start, date)
else datetime.strptime(str(start), "%Y-%m-%d").date()
)
days_since = (today - start_d).days days_since = (today - start_d).days
return days_since >= 0 and days_since % interval == 0 return days_since >= 0 and days_since % interval == 0
return False return False
return True return True
def _get_nearest_scheduled_time(med):
"""Find the nearest scheduled time for a medication.
Looks at the medication's scheduled times and finds the one closest to now.
Returns the time as HH:MM string, or None if medication is as_needed.
"""
freq = med.get("frequency", "daily")
# PRN medications don't have scheduled times
if freq == "as_needed":
return None
times = med.get("times", [])
if not times:
return None
# Get current time
now = datetime.now().time()
now_minutes = now.hour * 60 + now.minute
# Find the time closest to now (within ±4 hours window)
best_time = None
best_diff = float("inf")
window_minutes = 4 * 60 # 4 hour window
for time_str in times:
try:
# Parse time string (e.g., "12:00")
hour, minute = map(int, time_str.split(":"))
time_minutes = hour * 60 + minute
# Calculate difference (handle wrap-around for times near midnight)
diff = abs(time_minutes - now_minutes)
# Also check if it's much earlier/later due to day boundary
alt_diff = abs((time_minutes + 24 * 60) - now_minutes)
diff = min(diff, alt_diff)
# Only consider times within the window
if diff <= window_minutes and diff < best_diff:
best_diff = diff
best_time = time_str
except (ValueError, AttributeError):
continue
# If no time within window, use the most recent past time
if not best_time:
for time_str in times:
try:
hour, minute = map(int, time_str.split(":"))
time_minutes = hour * 60 + minute
# If this time was earlier today, it's a candidate
if time_minutes <= now_minutes:
diff = now_minutes - time_minutes
if diff < best_diff:
best_diff = diff
best_time = time_str
except (ValueError, AttributeError):
continue
# If still no time found, use the first scheduled time
if not best_time and times:
best_time = times[0]
return best_time
def _compute_next_dose_date(med): def _compute_next_dose_date(med):
"""Compute the next dose date for every_n_days medications.""" """Compute the next dose date for every_n_days medications."""
interval = med.get("interval_days") interval = med.get("interval_days")
@@ -172,11 +98,7 @@ def _count_expected_doses(med, period_start, days):
start = med.get("start_date") start = med.get("start_date")
if not start: if not start:
return 0 return 0
start_d = ( start_d = start if isinstance(start, date) else datetime.strptime(str(start), "%Y-%m-%d").date()
start
if isinstance(start, date)
else datetime.strptime(str(start), "%Y-%m-%d").date()
)
count = 0 count = 0
for d in range(days): for d in range(days):
check_date = period_start + timedelta(days=d) check_date = period_start + timedelta(days=d)
@@ -203,19 +125,14 @@ def _log_local_date(created_at, user_tz):
def _count_logs_in_period(logs, period_start_str, action, user_tz=None): def _count_logs_in_period(logs, period_start_str, action, user_tz=None):
"""Count logs of a given action where created_at (local date) >= period_start.""" """Count logs of a given action where created_at (local date) >= period_start."""
return sum( return sum(
1 1 for log in logs
for log in logs
if log.get("action") == action if log.get("action") == action
and ( and (_log_local_date(log.get("created_at"), user_tz) if user_tz else str(log.get("created_at", ""))[:10]) >= period_start_str
_log_local_date(log.get("created_at"), user_tz)
if user_tz
else str(log.get("created_at", ""))[:10]
)
>= period_start_str
) )
def register(app): def register(app):
# ── Medications CRUD ────────────────────────────────────────── # ── Medications CRUD ──────────────────────────────────────────
@app.route("/api/medications", methods=["GET"]) @app.route("/api/medications", methods=["GET"])
@@ -224,9 +141,7 @@ def register(app):
user_uuid = _auth(flask.request) user_uuid = _auth(flask.request)
if not user_uuid: if not user_uuid:
return flask.jsonify({"error": "unauthorized"}), 401 return flask.jsonify({"error": "unauthorized"}), 401
meds = postgres.select( meds = postgres.select("medications", where={"user_uuid": user_uuid}, order_by="name")
"medications", where={"user_uuid": user_uuid}, order_by="name"
)
return flask.jsonify(meds), 200 return flask.jsonify(meds), 200
@app.route("/api/medications", methods=["POST"]) @app.route("/api/medications", methods=["POST"])
@@ -241,9 +156,7 @@ def register(app):
required = ["name", "dosage", "unit", "frequency"] required = ["name", "dosage", "unit", "frequency"]
missing = [f for f in required if not data.get(f)] missing = [f for f in required if not data.get(f)]
if missing: if missing:
return flask.jsonify( return flask.jsonify({"error": f"missing required fields: {', '.join(missing)}"}), 400
{"error": f"missing required fields: {', '.join(missing)}"}
), 400
row = { row = {
"id": str(uuid.uuid4()), "id": str(uuid.uuid4()),
@@ -261,11 +174,7 @@ def register(app):
} }
# Compute next_dose_date for interval meds # Compute next_dose_date for interval meds
if ( if data.get("frequency") == "every_n_days" and data.get("start_date") and data.get("interval_days"):
data.get("frequency") == "every_n_days"
and data.get("start_date")
and data.get("interval_days")
):
start = datetime.strptime(data["start_date"], "%Y-%m-%d").date() start = datetime.strptime(data["start_date"], "%Y-%m-%d").date()
today = tz.user_today() today = tz.user_today()
if start > today: if start > today:
@@ -276,9 +185,7 @@ def register(app):
if remainder == 0: if remainder == 0:
row["next_dose_date"] = today.isoformat() row["next_dose_date"] = today.isoformat()
else: else:
row["next_dose_date"] = ( row["next_dose_date"] = (today + timedelta(days=data["interval_days"] - remainder)).isoformat()
today + timedelta(days=data["interval_days"] - remainder)
).isoformat()
med = postgres.insert("medications", _wrap_json(row)) med = postgres.insert("medications", _wrap_json(row))
return flask.jsonify(med), 201 return flask.jsonify(med), 201
@@ -303,30 +210,17 @@ def register(app):
data = flask.request.get_json() data = flask.request.get_json()
if not data: if not data:
return flask.jsonify({"error": "missing body"}), 400 return flask.jsonify({"error": "missing body"}), 400
existing = postgres.select_one( existing = postgres.select_one("medications", {"id": med_id, "user_uuid": user_uuid})
"medications", {"id": med_id, "user_uuid": user_uuid}
)
if not existing: if not existing:
return flask.jsonify({"error": "not found"}), 404 return flask.jsonify({"error": "not found"}), 404
allowed = [ allowed = [
"name", "name", "dosage", "unit", "frequency", "times", "notes", "active",
"dosage", "days_of_week", "interval_days", "start_date", "next_dose_date",
"unit",
"frequency",
"times",
"notes",
"active",
"days_of_week",
"interval_days",
"start_date",
"next_dose_date",
] ]
updates = {k: v for k, v in data.items() if k in allowed} updates = {k: v for k, v in data.items() if k in allowed}
if not updates: if not updates:
return flask.jsonify({"error": "no valid fields to update"}), 400 return flask.jsonify({"error": "no valid fields to update"}), 400
result = postgres.update( result = postgres.update("medications", _wrap_json(updates), {"id": med_id, "user_uuid": user_uuid})
"medications", _wrap_json(updates), {"id": med_id, "user_uuid": user_uuid}
)
return flask.jsonify(result[0] if result else {}), 200 return flask.jsonify(result[0] if result else {}), 200
@app.route("/api/medications/<med_id>", methods=["DELETE"]) @app.route("/api/medications/<med_id>", methods=["DELETE"])
@@ -335,9 +229,7 @@ def register(app):
user_uuid = _auth(flask.request) user_uuid = _auth(flask.request)
if not user_uuid: if not user_uuid:
return flask.jsonify({"error": "unauthorized"}), 401 return flask.jsonify({"error": "unauthorized"}), 401
existing = postgres.select_one( existing = postgres.select_one("medications", {"id": med_id, "user_uuid": user_uuid})
"medications", {"id": med_id, "user_uuid": user_uuid}
)
if not existing: if not existing:
return flask.jsonify({"error": "not found"}), 404 return flask.jsonify({"error": "not found"}), 404
postgres.delete("med_logs", {"medication_id": med_id}) postgres.delete("med_logs", {"medication_id": med_id})
@@ -356,19 +248,12 @@ def register(app):
if not med: if not med:
return flask.jsonify({"error": "not found"}), 404 return flask.jsonify({"error": "not found"}), 404
data = flask.request.get_json() or {} data = flask.request.get_json() or {}
# Determine scheduled_time
scheduled_time = data.get("scheduled_time")
if not scheduled_time:
# Auto-determine from medication schedule
scheduled_time = _get_nearest_scheduled_time(med)
log_entry = { log_entry = {
"id": str(uuid.uuid4()), "id": str(uuid.uuid4()),
"medication_id": med_id, "medication_id": med_id,
"user_uuid": user_uuid, "user_uuid": user_uuid,
"action": "taken", "action": "taken",
"scheduled_time": scheduled_time, "scheduled_time": data.get("scheduled_time"),
"notes": data.get("notes"), "notes": data.get("notes"),
} }
log = postgres.insert("med_logs", log_entry) log = postgres.insert("med_logs", log_entry)
@@ -376,9 +261,7 @@ def register(app):
if med.get("frequency") == "every_n_days" and med.get("interval_days"): if med.get("frequency") == "every_n_days" and med.get("interval_days"):
next_date = _compute_next_dose_date(med) next_date = _compute_next_dose_date(med)
if next_date: if next_date:
postgres.update( postgres.update("medications", {"next_dose_date": next_date}, {"id": med_id})
"medications", {"next_dose_date": next_date}, {"id": med_id}
)
return flask.jsonify(log), 201 return flask.jsonify(log), 201
@app.route("/api/medications/<med_id>/skip", methods=["POST"]) @app.route("/api/medications/<med_id>/skip", methods=["POST"])
@@ -391,19 +274,12 @@ def register(app):
if not med: if not med:
return flask.jsonify({"error": "not found"}), 404 return flask.jsonify({"error": "not found"}), 404
data = flask.request.get_json() or {} data = flask.request.get_json() or {}
# Determine scheduled_time
scheduled_time = data.get("scheduled_time")
if not scheduled_time:
# Auto-determine from medication schedule
scheduled_time = _get_nearest_scheduled_time(med)
log_entry = { log_entry = {
"id": str(uuid.uuid4()), "id": str(uuid.uuid4()),
"medication_id": med_id, "medication_id": med_id,
"user_uuid": user_uuid, "user_uuid": user_uuid,
"action": "skipped", "action": "skipped",
"scheduled_time": scheduled_time, "scheduled_time": data.get("scheduled_time"),
"notes": data.get("reason"), "notes": data.get("reason"),
} }
log = postgres.insert("med_logs", log_entry) log = postgres.insert("med_logs", log_entry)
@@ -411,9 +287,7 @@ def register(app):
if med.get("frequency") == "every_n_days" and med.get("interval_days"): if med.get("frequency") == "every_n_days" and med.get("interval_days"):
next_date = _compute_next_dose_date(med) next_date = _compute_next_dose_date(med)
if next_date: if next_date:
postgres.update( postgres.update("medications", {"next_dose_date": next_date}, {"id": med_id})
"medications", {"next_dose_date": next_date}, {"id": med_id}
)
return flask.jsonify(log), 201 return flask.jsonify(log), 201
@app.route("/api/medications/<med_id>/snooze", methods=["POST"]) @app.route("/api/medications/<med_id>/snooze", methods=["POST"])
@@ -461,9 +335,7 @@ def register(app):
if not user_uuid: if not user_uuid:
return flask.jsonify({"error": "unauthorized"}), 401 return flask.jsonify({"error": "unauthorized"}), 401
meds = postgres.select( meds = postgres.select("medications", where={"user_uuid": user_uuid, "active": True})
"medications", where={"user_uuid": user_uuid, "active": True}
)
now = tz.user_now() now = tz.user_now()
user_tz = now.tzinfo user_tz = now.tzinfo
today = now.date() today = now.date()
@@ -499,15 +371,13 @@ def register(app):
and _log_local_date(log.get("created_at"), user_tz) == today_str and _log_local_date(log.get("created_at"), user_tz) == today_str
] ]
result.append( result.append({
{
"medication": med, "medication": med,
"scheduled_times": [] if is_prn else med.get("times", []), "scheduled_times": [] if is_prn else med.get("times", []),
"taken_times": today_taken, "taken_times": today_taken,
"skipped_times": today_skipped, "skipped_times": today_skipped,
"is_prn": is_prn, "is_prn": is_prn,
} })
)
seen_med_ids.add(med["id"]) seen_med_ids.add(med["id"])
# Late night pass (22:00+): include next-day meds scheduled 00:00-02:00 # Late night pass (22:00+): include next-day meds scheduled 00:00-02:00
@@ -545,16 +415,14 @@ def register(app):
and _log_local_date(log.get("created_at"), user_tz) == tomorrow_str and _log_local_date(log.get("created_at"), user_tz) == tomorrow_str
] ]
result.append( result.append({
{
"medication": med, "medication": med,
"scheduled_times": early_times, "scheduled_times": early_times,
"taken_times": tomorrow_taken, "taken_times": tomorrow_taken,
"skipped_times": tomorrow_skipped, "skipped_times": tomorrow_skipped,
"is_prn": False, "is_prn": False,
"is_next_day": True, "is_next_day": True,
} })
)
seen_med_ids.add(med["id"]) seen_med_ids.add(med["id"])
# Early morning pass (<02:00): include previous-day meds scheduled 22:00-23:59 # Early morning pass (<02:00): include previous-day meds scheduled 22:00-23:59
@@ -592,16 +460,14 @@ def register(app):
and _log_local_date(log.get("created_at"), user_tz) == yesterday_str and _log_local_date(log.get("created_at"), user_tz) == yesterday_str
] ]
result.append( result.append({
{
"medication": med, "medication": med,
"scheduled_times": late_times, "scheduled_times": late_times,
"taken_times": yesterday_taken, "taken_times": yesterday_taken,
"skipped_times": yesterday_skipped, "skipped_times": yesterday_skipped,
"is_prn": False, "is_prn": False,
"is_previous_day": True, "is_previous_day": True,
} })
)
seen_med_ids.add(med["id"]) seen_med_ids.add(med["id"])
return flask.jsonify(result), 200 return flask.jsonify(result), 200
@@ -615,9 +481,7 @@ def register(app):
if not user_uuid: if not user_uuid:
return flask.jsonify({"error": "unauthorized"}), 401 return flask.jsonify({"error": "unauthorized"}), 401
num_days = flask.request.args.get("days", 30, type=int) num_days = flask.request.args.get("days", 30, type=int)
meds = postgres.select( meds = postgres.select("medications", where={"user_uuid": user_uuid, "active": True})
"medications", where={"user_uuid": user_uuid, "active": True}
)
now = tz.user_now() now = tz.user_now()
user_tz = now.tzinfo user_tz = now.tzinfo
today = now.date() today = now.date()
@@ -641,8 +505,7 @@ def register(app):
else: else:
adherence_pct = 0 adherence_pct = 0
result.append( result.append({
{
"medication_id": med["id"], "medication_id": med["id"],
"name": med["name"], "name": med["name"],
"taken": taken, "taken": taken,
@@ -650,8 +513,7 @@ def register(app):
"expected": expected, "expected": expected,
"adherence_percent": adherence_pct, "adherence_percent": adherence_pct,
"is_prn": is_prn, "is_prn": is_prn,
} })
)
return flask.jsonify(result), 200 return flask.jsonify(result), 200
@app.route("/api/medications/<med_id>/adherence", methods=["GET"]) @app.route("/api/medications/<med_id>/adherence", methods=["GET"])
@@ -685,8 +547,7 @@ def register(app):
else: else:
adherence_pct = 0 adherence_pct = 0
return flask.jsonify( return flask.jsonify({
{
"medication_id": med_id, "medication_id": med_id,
"name": med["name"], "name": med["name"],
"taken": taken, "taken": taken,
@@ -694,8 +555,7 @@ def register(app):
"expected": expected, "expected": expected,
"adherence_percent": adherence_pct, "adherence_percent": adherence_pct,
"is_prn": is_prn, "is_prn": is_prn,
} }), 200
), 200
# ── Refills ─────────────────────────────────────────────────── # ── Refills ───────────────────────────────────────────────────
@@ -715,9 +575,7 @@ def register(app):
updates = {k: v for k, v in data.items() if k in allowed} updates = {k: v for k, v in data.items() if k in allowed}
if not updates: if not updates:
return flask.jsonify({"error": "no valid fields to update"}), 400 return flask.jsonify({"error": "no valid fields to update"}), 400
result = postgres.update( result = postgres.update("medications", updates, {"id": med_id, "user_uuid": user_uuid})
"medications", updates, {"id": med_id, "user_uuid": user_uuid}
)
return flask.jsonify(result[0] if result else {}), 200 return flask.jsonify(result[0] if result else {}), 200
@app.route("/api/medications/refills-due", methods=["GET"]) @app.route("/api/medications/refills-due", methods=["GET"])

View File

@@ -4,10 +4,190 @@ Medications command handler - bot-side hooks for medication management
import asyncio import asyncio
import re import re
from datetime import datetime, timedelta, timezone
from bot.command_registry import register_module from bot.command_registry import register_module
import ai.parser as ai_parser import ai.parser as ai_parser
def _get_nearest_scheduled_time(times, user_tz=None):
"""Find the nearest scheduled time in user's timezone.
Args:
times: List of time strings like ["08:00", "20:00"]
user_tz: pytz timezone object for the user
Returns the time as HH:MM string, or None if no times provided.
"""
if not times:
return None
# Get current time in user's timezone
if user_tz is None:
# Default to UTC if no timezone provided
user_tz = timezone.utc
now = datetime.now(user_tz)
now_minutes = now.hour * 60 + now.minute
# Find the time closest to now (within ±4 hours window)
best_time = None
best_diff = float("inf")
window_minutes = 4 * 60 # 4 hour window
for time_str in times:
try:
# Parse time string (e.g., "12:00")
hour, minute = map(int, time_str.split(":"))
time_minutes = hour * 60 + minute
# Calculate difference
diff = abs(time_minutes - now_minutes)
# Only consider times within the window
if diff <= window_minutes and diff < best_diff:
best_diff = diff
best_time = time_str
except (ValueError, AttributeError):
continue
# If no time within window, use the most recent past time
if best_time is None:
# Get current time in user's timezone again for reference
now = datetime.now(user_tz)
now_minutes = now.hour * 60 + now.minute
# Find the most recent past time
past_times = []
for time_str in times:
try:
hour, minute = map(int, time_str.split(":"))
time_minutes = hour * 60 + minute
# If time is in the past today, calculate minutes since then
if time_minutes <= now_minutes:
past_times.append((time_minutes, time_str))
else:
# If time is in the future, consider it as yesterday's time
past_times.append((time_minutes - 24 * 60, time_str))
except (ValueError, AttributeError):
continue
if past_times:
# Find the time closest to now (most recent past)
past_times.sort()
best_time = past_times[-1][1]
return best_time
if not best_time:
for time_str in times:
try:
hour, minute = map(int, time_str.split(":"))
time_minutes = hour * 60 + minute
# If this time was earlier today, it's a candidate
if time_minutes <= now_minutes:
diff = now_minutes - time_minutes
if diff < best_diff:
best_diff = diff
best_time = time_str
except (ValueError, AttributeError):
continue
# If still no time found, use the first scheduled time
if not best_time and times:
best_time = times[0]
return best_time
async def _get_user_timezone(bot, user_id):
"""Check if user has timezone set, ask for it if not.
Returns the timezone string or None if user cancels.
"""
# Check if user has timezone set
user_data = await bot.api.get_user_data(user_id)
if user_data and user_data.get('timezone'):
return user_data['timezone']
# Ask user for their timezone
await bot.send_dm(user_id, "🕐 I don't have your timezone set yet. Could you please tell me your timezone?\n\n" +
"You can provide it in various formats:\n" +
"- Timezone name (e.g., 'America/New_York', 'Europe/London')\n" +
"- UTC offset (e.g., 'UTC+2', '-05:00')\n" +
"- Common abbreviations (e.g., 'EST', 'PST')\n\n" +
"Please reply with your timezone and I'll set it up for you!")
# Wait for user response (simplified - in real implementation this would be more complex)
# For now, we'll just return None to indicate we need to handle this differently
return None
await bot.send_dm(user_id, "I didn't understand that timezone format. Please say something like:\n"
'- "UTC-8" or "-8" for Pacific Time\n'
'- "UTC+1" or "+1" for Central European Time\n'
'- "PST", "EST", "CST", "MST" for US timezones')
return None
# Check if user has timezone set in preferences
resp, status = api_request("get", "/api/preferences", token)
if status == 200 and resp:
offset = resp.get("timezone_offset")
if offset is not None:
return offset
# No timezone set - need to ask user
return None
def _parse_timezone(user_input):
"""Parse timezone string to offset in minutes.
Examples:
"UTC-8" -> 480 (8 hours behind UTC)
"-8" -> 480
"PST" -> 480
"EST" -> 300
"+5:30" -> -330
Returns offset in minutes (positive = behind UTC) or None if invalid.
"""
user_input = user_input.strip().upper()
# Common timezone abbreviations
tz_map = {
"PST": 480,
"PDT": 420,
"MST": 420,
"MDT": 360,
"CST": 360,
"CDT": 300,
"EST": 300,
"EDT": 240,
"GMT": 0,
"UTC": 0,
}
if user_input in tz_map:
return tz_map[user_input]
# Try to parse offset format
# Remove UTC prefix if present
if user_input.startswith("UTC"):
user_input = user_input[3:]
# Match patterns like -8, +5, -5:30, +5:30
match = re.match(r"^([+-])?(\d+)(?::(\d+))?$", user_input)
if match:
sign = -1 if match.group(1) == "-" else 1
hours = int(match.group(2))
minutes = int(match.group(3)) if match.group(3) else 0
# Convert to offset minutes (positive = behind UTC)
# If user says UTC-8, they're 8 hours BEHIND UTC, so offset is +480
offset_minutes = (hours * 60 + minutes) * sign * -1
return offset_minutes
return None
async def _get_scheduled_time_from_context(message, med_name): async def _get_scheduled_time_from_context(message, med_name):
"""Fetch recent messages and extract scheduled time from medication reminder. """Fetch recent messages and extract scheduled time from medication reminder.
@@ -164,22 +344,48 @@ async def handle_medication(message, session, parsed):
await message.channel.send("Which medication did you take?") await message.channel.send("Which medication did you take?")
return return
# Check if we have user's timezone
timezone_offset = await _get_user_timezone(message, session, token)
if timezone_offset is None:
# Need to ask for timezone first
if "pending_confirmations" not in session:
session["pending_confirmations"] = {}
# Store that we're waiting for timezone, along with the med info
session["pending_confirmations"]["timezone"] = {
"action": "take",
"medication_id": med_id,
"name": name,
}
await message.channel.send(
"📍 I need to know your timezone to track medications correctly.\n\n"
'What timezone are you in? (e.g., "UTC-8", "PST", "EST", "+1")'
)
return
# Try to get scheduled time from recent reminder context # Try to get scheduled time from recent reminder context
scheduled_time = await _get_scheduled_time_from_context(message, name) scheduled_time = await _get_scheduled_time_from_context(message, name)
# If not found in context, calculate from medication schedule
if not scheduled_time:
# Get medication details to find scheduled times
med_resp, med_status = api_request(
"get", f"/api/medications/{med_id}", token
)
if med_status == 200 and med_resp:
times = med_resp.get("times", [])
scheduled_time = _get_nearest_scheduled_time(times, timezone_offset)
# Build request body with scheduled_time if found # Build request body with scheduled_time if found
request_body = {} request_body = {}
if scheduled_time: if scheduled_time:
request_body["scheduled_time"] = scheduled_time request_body["scheduled_time"] = scheduled_time
print(
f"[DEBUG] About to call API: POST /api/medications/{med_id}/take with body: {request_body}",
flush=True,
)
resp, status = api_request( resp, status = api_request(
"post", f"/api/medications/{med_id}/take", token, request_body "post", f"/api/medications/{med_id}/take", token, request_body
) )
print(f"[DEBUG] API response: status={status}, resp={resp}", flush=True)
if status == 201: if status == 201:
if scheduled_time: if scheduled_time:
await message.channel.send( await message.channel.send(