#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Zapise poznamku lekare do Medevio kalendare (color=CHARCOAL). Hlavni funkce: `zapis_poznamku()` - bere parametry: calendar_id UUID kalendare (Vlado / manzelka / ...) den date nebo str 'YYYY-MM-DD' cas str 'HH:MM' nebo time trvani_min int - delka v minutach poznamka str - text perioda None | str - "DAILY", "WEEKDAYS", atd. (zatim NotImplemented) color ECRFIconColor enum, default CHARCOAL clinic_slug default mudr-buzalkova Vrati id vytvorene rezervace (str). CLI: python zapis_poznamky.py --den 2026-06-03 --cas 09:00 --trvani 5 --poznamka "Text" python zapis_poznamky.py --den 2026-06-03 --cas 09:00 --trvani 5 --poznamka "Text" --kalendar manzelka """ import sys import json import argparse from pathlib import Path from datetime import datetime, date, time as dtime, timedelta import requests from dateutil import tz try: sys.stdout.reconfigure(encoding="utf-8") except AttributeError: pass GRAPHQL_URL = "https://api.medevio.cz/graphql" CLINIC_SLUG = "mudr-buzalkova" PRAGUE_TZ = tz.gettz("Europe/Prague") # Pojmenovane kalendare - viz pamet project-medevio-kalendar CALENDARS = { "vlado": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca", "manzelka": "144c4e12-347c-49ca-9ec0-8ca965a4470d", } DEFAULT_CALENDAR = "vlado" BASE_DIR = Path(__file__).resolve().parent TOKEN_PATH = BASE_DIR / "token.txt" DEBUG_DIR = BASE_DIR / "debug" MUTATION = """mutation CreateReservation_MakeReservationByDoctor( $clinicSlug: String!, $color: ECRFIconColor, $note: String!, $timeSlotInput: TimeSlotInput! ) { reservation: makeReservationByDoctor( clinicSlug: $clinicSlug color: $color note: $note timeSlotInput: $timeSlotInput ) { id __typename } }""" def _load_token() -> str: token = TOKEN_PATH.read_text(encoding="utf-8").strip() if token.startswith("Bearer "): token = token.split(" ", 1)[1] return token def _headers() -> dict: return { "content-type": "application/json", "authorization": f"Bearer {_load_token()}", "origin": "https://my.medevio.cz", "referer": "https://my.medevio.cz/", } def _to_utc_iso(dt: datetime) -> str: if dt.tzinfo is None: dt = dt.replace(tzinfo=PRAGUE_TZ) return dt.astimezone(tz.UTC).strftime("%Y-%m-%dT%H:%M:%S.000Z") def _resolve_calendar(calendar) -> str: """Prijme UUID nebo nazev ('vlado', 'manzelka'). Vrati UUID.""" if calendar in CALENDARS: return CALENDARS[calendar] if isinstance(calendar, str) and len(calendar) == 36 and calendar.count("-") == 4: return calendar raise ValueError(f"Neznamy kalendar: {calendar!r}. Pouzij UUID nebo jeden z {list(CALENDARS)}.") def _resolve_day(den) -> date: if isinstance(den, date) and not isinstance(den, datetime): return den if isinstance(den, datetime): return den.date() return datetime.strptime(str(den), "%Y-%m-%d").date() def _resolve_time(cas) -> dtime: if isinstance(cas, dtime): return cas return datetime.strptime(str(cas), "%H:%M").time() def zapis_poznamku( calendar: str = DEFAULT_CALENDAR, den=None, cas=None, trvani_min: int = 5, poznamka: str = "", perioda: str | None = None, color: str = "CHARCOAL", clinic_slug: str = CLINIC_SLUG, save_debug: bool = True, ) -> str: """Vytvori poznamku lekare v Medevio kalendari. Vraci id rezervace.""" if perioda is not None: raise NotImplementedError( "Periodicita zatim neni implementovana - neznam format payloadu. " "Zachyt jednu opakujici se rezervaci pres Claude in Chrome a doplnime." ) if den is None or cas is None: raise ValueError("Musis zadat 'den' a 'cas'.") calendar_id = _resolve_calendar(calendar) d = _resolve_day(den) t = _resolve_time(cas) start_dt = datetime.combine(d, t).replace(tzinfo=PRAGUE_TZ) end_dt = start_dt + timedelta(minutes=int(trvani_min)) payload = { "operationName": "CreateReservation_MakeReservationByDoctor", "variables": { "clinicSlug": clinic_slug, "color": color, "note": poznamka, "timeSlotInput": { "calendarId": calendar_id, "start": _to_utc_iso(start_dt), "end": _to_utc_iso(end_dt), }, }, "query": MUTATION, } r = requests.post(GRAPHQL_URL, headers=_headers(), data=json.dumps(payload), timeout=30) r.raise_for_status() data = r.json() if save_debug: DEBUG_DIR.mkdir(exist_ok=True) debug_path = DEBUG_DIR / f"poznamka_{datetime.now():%Y%m%d_%H%M%S}.json" debug_path.write_text( json.dumps({"request": payload["variables"], "response": data}, ensure_ascii=False, indent=2), encoding="utf-8", ) print(f"[debug] {debug_path}") if "errors" in data: raise RuntimeError(f"GraphQL error: {data['errors']}") res_id = data["data"]["reservation"]["id"] print(f"OK: {d} {t:%H:%M} +{trvani_min}min '{poznamka}' -> {res_id}") return res_id def main(): ap = argparse.ArgumentParser(description="Zapis poznamku lekare do Medevio kalendare.") ap.add_argument("--kalendar", default=DEFAULT_CALENDAR, help=f"Jmeno ({'/'.join(CALENDARS)}) nebo UUID. Default '{DEFAULT_CALENDAR}'.") ap.add_argument("--den", required=True, help="YYYY-MM-DD") ap.add_argument("--cas", required=True, help="HH:MM (lokalni cas Europe/Prague)") ap.add_argument("--trvani", type=int, default=5, help="delka v minutach (default 5)") ap.add_argument("--poznamka", required=True, help="text poznamky") ap.add_argument("--perioda", default=None, help="opakovani (zatim NotImplemented)") ap.add_argument("--color", default="CHARCOAL") args = ap.parse_args() zapis_poznamku( calendar=args.kalendar, den=args.den, cas=args.cas, trvani_min=args.trvani, poznamka=args.poznamka, perioda=args.perioda, color=args.color, ) if __name__ == "__main__": main()