notebookvb
This commit is contained in:
@@ -0,0 +1,385 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Cteni agendy z Medevio kalendare.
|
||||||
|
|
||||||
|
Hlavni funkce: `list_agendu(start, end=None, calendar=None)`
|
||||||
|
start date | datetime | str 'YYYY-MM-DD' nebo 'YYYY-MM-DD HH:MM'
|
||||||
|
end to stejne; pokud None, bere se konec dne `start` (23:59:59)
|
||||||
|
calendar None = oba (vlado + manzelka), nebo "vlado" / "manzelka" / UUID,
|
||||||
|
nebo list techto hodnot
|
||||||
|
|
||||||
|
Vraci list dictu serazenych podle start. Kazdy dict obsahuje pole `calendar`
|
||||||
|
(jmeno) navic.
|
||||||
|
|
||||||
|
CLI:
|
||||||
|
python agenda_dne.py # interaktivne se zepta
|
||||||
|
python agenda_dne.py --od 2026-06-03 --do 2026-06-03 --kalendar vlado
|
||||||
|
python agenda_dne.py --od 2026-06-01 --do 2026-06-07 # tyden, oba
|
||||||
|
python agenda_dne.py --den 2026-06-03 # zkratka pro jeden den
|
||||||
|
python agenda_dne.py --den dnes
|
||||||
|
python agenda_dne.py --den +1 --kalendar manzelka
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import argparse
|
||||||
|
from pathlib import Path
|
||||||
|
from datetime import datetime, date, timedelta
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from dateutil import parser as dtparser, 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",
|
||||||
|
}
|
||||||
|
|
||||||
|
BASE_DIR = Path(__file__).resolve().parent
|
||||||
|
TOKEN_PATH = BASE_DIR / "token.txt"
|
||||||
|
DEBUG_DIR = BASE_DIR / "debug"
|
||||||
|
|
||||||
|
QUERY = """query Agenda_ListAll(
|
||||||
|
$calendarIds: [UUID!]!, $clinicSlug: String!,
|
||||||
|
$locale: Locale!, $since: DateTime!, $until: DateTime!
|
||||||
|
) {
|
||||||
|
reservations: listClinicReservations(
|
||||||
|
clinicSlug: $clinicSlug, calendarIds: $calendarIds,
|
||||||
|
since: $since, until: $until
|
||||||
|
) {
|
||||||
|
id start end note done color canceledAt calendarId
|
||||||
|
request {
|
||||||
|
id displayTitle(locale: $locale)
|
||||||
|
extendedPatient {
|
||||||
|
id name surname dob phone identificationNumber
|
||||||
|
insuranceCompanyObject { code shortName }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
recurringReservations: listClinicRecurringReservations(
|
||||||
|
clinicSlug: $clinicSlug, calendarIds: $calendarIds,
|
||||||
|
since: $since, until: $until
|
||||||
|
) {
|
||||||
|
recurringReservation {
|
||||||
|
id calendarId color note
|
||||||
|
rrule { frequency interval dtstart tzid byweekday bymonthday byweekno }
|
||||||
|
}
|
||||||
|
instances { start end note color }
|
||||||
|
}
|
||||||
|
}"""
|
||||||
|
|
||||||
|
|
||||||
|
# ==================== Helpery ====================
|
||||||
|
|
||||||
|
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 _is_uuid(s: str) -> bool:
|
||||||
|
return isinstance(s, str) and len(s) == 36 and s.count("-") == 4
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_calendars(calendar) -> list[tuple[str, str]]:
|
||||||
|
"""Vraci list (jmeno, uuid). None = oba pojmenovane."""
|
||||||
|
if calendar is None:
|
||||||
|
return list(CALENDARS.items())
|
||||||
|
items = calendar if isinstance(calendar, list) else [calendar]
|
||||||
|
out = []
|
||||||
|
for c in items:
|
||||||
|
if c in CALENDARS:
|
||||||
|
out.append((c, CALENDARS[c]))
|
||||||
|
elif _is_uuid(c):
|
||||||
|
# zkusime najit jmeno
|
||||||
|
name = next((n for n, u in CALENDARS.items() if u == c), c)
|
||||||
|
out.append((name, c))
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Neznamy kalendar: {c!r}")
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def _to_dt(value, end_of_day: bool = False) -> datetime:
|
||||||
|
"""Prevede date/datetime/str na datetime s Europe/Prague timezone."""
|
||||||
|
if isinstance(value, datetime):
|
||||||
|
dt = value
|
||||||
|
elif isinstance(value, date):
|
||||||
|
dt = datetime.combine(
|
||||||
|
value,
|
||||||
|
datetime.max.time().replace(microsecond=0) if end_of_day else datetime.min.time(),
|
||||||
|
)
|
||||||
|
elif isinstance(value, str):
|
||||||
|
s = value.strip().replace("T", " ")
|
||||||
|
if " " in s:
|
||||||
|
dt = datetime.strptime(s, "%Y-%m-%d %H:%M")
|
||||||
|
else:
|
||||||
|
d = datetime.strptime(s, "%Y-%m-%d").date()
|
||||||
|
dt = datetime.combine(
|
||||||
|
d,
|
||||||
|
datetime.max.time().replace(microsecond=0) if end_of_day else datetime.min.time(),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise TypeError(f"Nelze prevest na datetime: {value!r}")
|
||||||
|
if dt.tzinfo is None:
|
||||||
|
dt = dt.replace(tzinfo=PRAGUE_TZ)
|
||||||
|
return dt
|
||||||
|
|
||||||
|
|
||||||
|
def _to_utc_iso(dt: datetime) -> str:
|
||||||
|
return dt.astimezone(tz.UTC).strftime("%Y-%m-%dT%H:%M:%S.000Z")
|
||||||
|
|
||||||
|
|
||||||
|
# ==================== Hlavni funkce ====================
|
||||||
|
|
||||||
|
def list_agendu(
|
||||||
|
start,
|
||||||
|
end=None,
|
||||||
|
calendar=None,
|
||||||
|
save_debug: bool = True,
|
||||||
|
) -> list[dict]:
|
||||||
|
"""Vraci rezervace v zadanem rozmezi pro vybrane kalendare.
|
||||||
|
|
||||||
|
Pokud `end` neni zadan, pouzije se konec stejneho dne jako `start`.
|
||||||
|
Pokud `calendar` je None, vrati se oba pojmenovane kalendare slouceny.
|
||||||
|
"""
|
||||||
|
start_dt = _to_dt(start, end_of_day=False)
|
||||||
|
if end is None:
|
||||||
|
end_dt = _to_dt(start_dt.date(), end_of_day=True)
|
||||||
|
else:
|
||||||
|
end_dt = _to_dt(end, end_of_day=True)
|
||||||
|
|
||||||
|
cals = _resolve_calendars(calendar)
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"operationName": "Agenda_ListAll",
|
||||||
|
"variables": {
|
||||||
|
"calendarIds": [uuid for _, uuid in cals],
|
||||||
|
"clinicSlug": CLINIC_SLUG,
|
||||||
|
"since": _to_utc_iso(start_dt),
|
||||||
|
"until": _to_utc_iso(end_dt),
|
||||||
|
"locale": "cs",
|
||||||
|
},
|
||||||
|
"query": QUERY,
|
||||||
|
}
|
||||||
|
|
||||||
|
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"agenda_{start_dt:%Y%m%d}_{end_dt:%Y%m%d}_{datetime.now():%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']}")
|
||||||
|
|
||||||
|
uuid_to_name = {uuid: name for name, uuid in cals}
|
||||||
|
parsed = []
|
||||||
|
|
||||||
|
# 1) Jednorazove rezervace
|
||||||
|
for res in data["data"].get("reservations") or []:
|
||||||
|
if res.get("canceledAt"):
|
||||||
|
continue
|
||||||
|
s = dtparser.isoparse(res["start"]).astimezone(PRAGUE_TZ)
|
||||||
|
e = dtparser.isoparse(res["end"]).astimezone(PRAGUE_TZ)
|
||||||
|
req = res.get("request") or {}
|
||||||
|
pat = req.get("extendedPatient") or {}
|
||||||
|
ins = pat.get("insuranceCompanyObject") or {}
|
||||||
|
request_id = req.get("id") or ""
|
||||||
|
parsed.append({
|
||||||
|
"typ": "pacient" if request_id else "poznamka",
|
||||||
|
"calendar": uuid_to_name.get(res.get("calendarId"), res.get("calendarId")),
|
||||||
|
"calendar_id": res.get("calendarId"),
|
||||||
|
"start": s,
|
||||||
|
"end": e,
|
||||||
|
"title": req.get("displayTitle") or "",
|
||||||
|
"patient": f"{pat.get('surname','')} {pat.get('name','')}".strip(),
|
||||||
|
"dob": pat.get("dob") or "",
|
||||||
|
"rc": pat.get("identificationNumber") or "",
|
||||||
|
"phone": pat.get("phone") or "",
|
||||||
|
"insurance": ins.get("shortName") or "",
|
||||||
|
"insurance_code": ins.get("code") or "",
|
||||||
|
"note": (res.get("note") or "").strip(),
|
||||||
|
"done": bool(res.get("done")),
|
||||||
|
"color": res.get("color") or "",
|
||||||
|
"reservation_id": res["id"],
|
||||||
|
"request_id": request_id,
|
||||||
|
"patient_id": pat.get("id") or "",
|
||||||
|
"recurring": False,
|
||||||
|
})
|
||||||
|
|
||||||
|
# 2) Opakujici se - jednotlive instance v intervalu
|
||||||
|
for rr in data["data"].get("recurringReservations") or []:
|
||||||
|
rule = rr.get("recurringReservation") or {}
|
||||||
|
cal_id = rule.get("calendarId")
|
||||||
|
for inst in rr.get("instances") or []:
|
||||||
|
s = dtparser.isoparse(inst["start"]).astimezone(PRAGUE_TZ)
|
||||||
|
e = dtparser.isoparse(inst["end"]).astimezone(PRAGUE_TZ)
|
||||||
|
parsed.append({
|
||||||
|
"typ": "poznamka", # opakujici se vznikaji vzdy pres "Jina udalost"
|
||||||
|
"calendar": uuid_to_name.get(cal_id, cal_id),
|
||||||
|
"calendar_id": cal_id,
|
||||||
|
"start": s,
|
||||||
|
"end": e,
|
||||||
|
"title": "",
|
||||||
|
"patient": "",
|
||||||
|
"dob": "", "rc": "", "phone": "",
|
||||||
|
"insurance": "", "insurance_code": "",
|
||||||
|
"note": (inst.get("note") or rule.get("note") or "").strip(),
|
||||||
|
"done": False,
|
||||||
|
"color": inst.get("color") or rule.get("color") or "",
|
||||||
|
"reservation_id": rule.get("id"),
|
||||||
|
"request_id": "",
|
||||||
|
"patient_id": "",
|
||||||
|
"recurring": True,
|
||||||
|
"rrule": rule.get("rrule"),
|
||||||
|
})
|
||||||
|
|
||||||
|
parsed.sort(key=lambda x: (x["start"], x["calendar"]))
|
||||||
|
return parsed
|
||||||
|
|
||||||
|
|
||||||
|
# Zachovani zpetne kompatibility
|
||||||
|
def get_agenda(day, calendar=None) -> list[dict]:
|
||||||
|
"""Vraci agendu jednoho dne. Pro zpetnou kompat se starsim API."""
|
||||||
|
return list_agendu(day, end=day, calendar=calendar)
|
||||||
|
|
||||||
|
|
||||||
|
# ==================== Vystup ====================
|
||||||
|
|
||||||
|
def print_agenda(reservations: list[dict], header: str | None = None) -> None:
|
||||||
|
cz_dny = ["pondeli", "utery", "streda", "ctvrtek", "patek", "sobota", "nedele"]
|
||||||
|
|
||||||
|
if header is None:
|
||||||
|
if reservations:
|
||||||
|
dates = sorted({r["start"].date() for r in reservations})
|
||||||
|
if len(dates) == 1:
|
||||||
|
header = f"Agenda {dates[0].isoformat()} ({cz_dny[dates[0].weekday()]})"
|
||||||
|
else:
|
||||||
|
header = f"Agenda {dates[0].isoformat()} - {dates[-1].isoformat()}"
|
||||||
|
else:
|
||||||
|
header = "Agenda"
|
||||||
|
|
||||||
|
print(header)
|
||||||
|
print("=" * len(header))
|
||||||
|
|
||||||
|
if not reservations:
|
||||||
|
print("(zadne rezervace)")
|
||||||
|
return
|
||||||
|
|
||||||
|
last_date = None
|
||||||
|
for r in reservations:
|
||||||
|
if r["start"].date() != last_date:
|
||||||
|
if last_date is not None:
|
||||||
|
print()
|
||||||
|
print(f"--- {r['start'].date().isoformat()} ({cz_dny[r['start'].weekday()]}) ---")
|
||||||
|
last_date = r["start"].date()
|
||||||
|
|
||||||
|
time_str = f"{r['start']:%H:%M}-{r['end']:%H:%M}"
|
||||||
|
cal = f"[{r['calendar']}]" if r["calendar"] else ""
|
||||||
|
typ = f"<{r.get('typ','?')}>"
|
||||||
|
flags = []
|
||||||
|
if r["done"]:
|
||||||
|
flags.append("HOTOVO")
|
||||||
|
if r.get("recurring"):
|
||||||
|
flags.append("OPAKOVANE")
|
||||||
|
flag_str = f" [{', '.join(flags)}]" if flags else ""
|
||||||
|
|
||||||
|
label = r["patient"] if r.get("typ") == "pacient" else (r.get("note") or "(bez popisu)")
|
||||||
|
line = f"{time_str} {cal} {typ} {label}"
|
||||||
|
if r["dob"]:
|
||||||
|
line += f" *{r['dob']}"
|
||||||
|
if r["insurance"]:
|
||||||
|
line += f" {r['insurance']}"
|
||||||
|
line += flag_str
|
||||||
|
print(line)
|
||||||
|
if r["title"]:
|
||||||
|
print(f" {r['title']}")
|
||||||
|
if r["note"]:
|
||||||
|
for ln in r["note"].splitlines():
|
||||||
|
print(f" poznamka: {ln}")
|
||||||
|
|
||||||
|
print()
|
||||||
|
print(f"Celkem: {len(reservations)} rezervaci")
|
||||||
|
|
||||||
|
|
||||||
|
# ==================== CLI ====================
|
||||||
|
|
||||||
|
def _parse_day_arg(arg: str | None) -> date:
|
||||||
|
if not arg or arg in ("dnes", "today"):
|
||||||
|
return date.today()
|
||||||
|
if arg in ("zitra", "tomorrow"):
|
||||||
|
return date.today() + timedelta(days=1)
|
||||||
|
if arg in ("vcera", "yesterday"):
|
||||||
|
return date.today() - timedelta(days=1)
|
||||||
|
if arg.startswith(("+", "-")) and arg[1:].isdigit():
|
||||||
|
return date.today() + timedelta(days=int(arg))
|
||||||
|
return datetime.strptime(arg, "%Y-%m-%d").date()
|
||||||
|
|
||||||
|
|
||||||
|
def _prompt_interactive() -> tuple[date, date, str | None]:
|
||||||
|
cz_dny = ["pondeli", "utery", "streda", "ctvrtek", "patek", "sobota", "nedele"]
|
||||||
|
today = date.today()
|
||||||
|
print("Cteni agendy z Medevio")
|
||||||
|
print(f"Dnes je {today.isoformat()} ({cz_dny[today.weekday()]})")
|
||||||
|
print()
|
||||||
|
print("Od (YYYY-MM-DD / +N / -N / dnes / zitra / vcera, Enter = dnes):")
|
||||||
|
od = _parse_day_arg(input("> ").strip() or None)
|
||||||
|
print(f"Do (Enter = stejny den jako od = {od.isoformat()}):")
|
||||||
|
do_raw = input("> ").strip()
|
||||||
|
do = _parse_day_arg(do_raw) if do_raw else od
|
||||||
|
print(f"Kalendar (vlado / manzelka / Enter = oba):")
|
||||||
|
cal = input("> ").strip() or None
|
||||||
|
return od, do, cal
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
ap = argparse.ArgumentParser(description="Cteni agendy z Medevio.")
|
||||||
|
ap.add_argument("--od", help="Pocatecni datum 'YYYY-MM-DD' / +N / -N / dnes/zitra/vcera")
|
||||||
|
ap.add_argument("--do", dest="do_", help="Koncove datum (default = stejny jako --od)")
|
||||||
|
ap.add_argument("--den", help="Zkratka: --od i --do nastaveny na tento den")
|
||||||
|
ap.add_argument("--kalendar", default=None,
|
||||||
|
help=f"{'/'.join(CALENDARS)} nebo UUID. Bez parametru = oba.")
|
||||||
|
args = ap.parse_args()
|
||||||
|
|
||||||
|
if args.den:
|
||||||
|
od = do = _parse_day_arg(args.den)
|
||||||
|
cal = args.kalendar
|
||||||
|
elif args.od:
|
||||||
|
od = _parse_day_arg(args.od)
|
||||||
|
do = _parse_day_arg(args.do_) if args.do_ else od
|
||||||
|
cal = args.kalendar
|
||||||
|
else:
|
||||||
|
od, do, cal = _prompt_interactive()
|
||||||
|
|
||||||
|
reservations = list_agendu(od, do, calendar=cal)
|
||||||
|
print_agenda(reservations)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"calendarIds": [
|
||||||
|
"144c4e12-347c-49ca-9ec0-8ca965a4470d"
|
||||||
|
],
|
||||||
|
"clinicSlug": "mudr-buzalkova",
|
||||||
|
"since": "2026-05-28T22:00:00.000Z",
|
||||||
|
"until": "2026-05-29T22:00:00.000Z",
|
||||||
|
"locale": "cs",
|
||||||
|
"emptyCalendarIds": false
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"data": {
|
||||||
|
"reservations": [
|
||||||
|
{
|
||||||
|
"id": "6e02c736-6060-41bb-90f5-a9dcd309bee4",
|
||||||
|
"start": "2026-05-29T09:40:00.000Z",
|
||||||
|
"end": "2026-05-29T09:50:00.000Z",
|
||||||
|
"note": null,
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"request": {
|
||||||
|
"id": "98b890a9-bc2b-42c8-859f-fe109f09e1f6",
|
||||||
|
"displayTitle": "Očkování - Černý kašel (kombinovaná vakcína Adacel [černý kašel, tetanus, záškrt])",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "92e7be7e-e41b-4181-afc3-624a82bd94f2",
|
||||||
|
"name": "Nicol",
|
||||||
|
"surname": "Slaninová",
|
||||||
|
"dob": "1978-12-20",
|
||||||
|
"phone": "+420777145986",
|
||||||
|
"identificationNumber": "7862202920",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 111,
|
||||||
|
"shortName": "VZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "e47d9c64-b84e-4a89-bb3e-77e96db55e84",
|
||||||
|
"start": "2026-05-29T08:45:00.000Z",
|
||||||
|
"end": "2026-05-29T09:30:00.000Z",
|
||||||
|
"note": null,
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"request": {
|
||||||
|
"id": "9154f33e-6724-450c-af58-3abd0a4778da",
|
||||||
|
"displayTitle": "Preventivní prohlídka nebo vstupní prohlídka",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "17a5563e-4044-4c67-b9fd-928be546ea5a",
|
||||||
|
"name": "Martin",
|
||||||
|
"surname": "Štoček",
|
||||||
|
"dob": "1989-10-19",
|
||||||
|
"phone": "+420604131463",
|
||||||
|
"identificationNumber": "8910193336",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 111,
|
||||||
|
"shortName": "VZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "8f0a84e9-1f88-4f94-b826-7364095284fc",
|
||||||
|
"start": "2026-05-29T10:00:00.000Z",
|
||||||
|
"end": "2026-05-29T10:05:00.000Z",
|
||||||
|
"note": "ukončit PN Pelcová E.",
|
||||||
|
"done": null,
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"canceledAt": null,
|
||||||
|
"request": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "565cf3f0-ad44-485f-9433-18e271f429c1",
|
||||||
|
"start": "2026-05-29T09:30:00.000Z",
|
||||||
|
"end": "2026-05-29T09:50:00.000Z",
|
||||||
|
"note": "",
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"request": {
|
||||||
|
"id": "4ae28457-ee0c-46f0-89b1-23075cfcbe81",
|
||||||
|
"displayTitle": "Konzultace zdravotního stavu ",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "88a2c4f3-ad3e-472b-899c-c86b72d6f2e7",
|
||||||
|
"name": "Hana",
|
||||||
|
"surname": "Hlavsová",
|
||||||
|
"dob": "1941-09-06",
|
||||||
|
"phone": null,
|
||||||
|
"identificationNumber": "415906003",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 111,
|
||||||
|
"shortName": "VZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c87c1cfe-2360-478c-8820-a9d92a47511e",
|
||||||
|
"start": "2026-05-29T09:50:00.000Z",
|
||||||
|
"end": "2026-05-29T10:00:00.000Z",
|
||||||
|
"note": null,
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"request": {
|
||||||
|
"id": "0067cd89-ccb0-4b23-9548-260e2efd2d45",
|
||||||
|
"displayTitle": "Odběry",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "fbb78b75-1c61-4915-8d06-1d7ceb6f9450",
|
||||||
|
"name": "Petra",
|
||||||
|
"surname": "Zelenková",
|
||||||
|
"dob": "1983-01-11",
|
||||||
|
"phone": "+420731585469",
|
||||||
|
"identificationNumber": "8351112693",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 207,
|
||||||
|
"shortName": "OZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "9b3ab4a3-47aa-4438-9dd7-5289d74a16a5",
|
||||||
|
"start": "2026-05-29T07:30:00.000Z",
|
||||||
|
"end": "2026-05-29T08:00:00.000Z",
|
||||||
|
"note": null,
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"request": {
|
||||||
|
"id": "c2dd4666-4be3-4543-ad02-bafb05694bd3",
|
||||||
|
"displayTitle": "Předoperační vyšetření",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "e6d965dd-b1ba-44c6-a0ba-915a83d45770",
|
||||||
|
"name": "Markéta",
|
||||||
|
"surname": "Bečicová",
|
||||||
|
"dob": "1967-08-12",
|
||||||
|
"phone": "+420736540111",
|
||||||
|
"identificationNumber": "6758120446",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 205,
|
||||||
|
"shortName": "ČPZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "86a379f8-3479-4c5e-86b8-550afc55491f",
|
||||||
|
"start": "2026-05-29T08:00:00.000Z",
|
||||||
|
"end": "2026-05-29T08:45:00.000Z",
|
||||||
|
"note": null,
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"request": {
|
||||||
|
"id": "97e97780-1b9d-4c4d-be99-f05b25cad2fa",
|
||||||
|
"displayTitle": "Preventivní prohlídka nebo vstupní prohlídka",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "a72e32cb-752e-4b3b-bcce-fca9f142c76a",
|
||||||
|
"name": "Eva",
|
||||||
|
"surname": "Zemanová",
|
||||||
|
"dob": "1939-09-12",
|
||||||
|
"phone": "+420739555303",
|
||||||
|
"identificationNumber": "395912079",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 111,
|
||||||
|
"shortName": "VZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,268 @@
|
|||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"calendarIds": [
|
||||||
|
"144c4e12-347c-49ca-9ec0-8ca965a4470d"
|
||||||
|
],
|
||||||
|
"clinicSlug": "mudr-buzalkova",
|
||||||
|
"since": "2026-06-02T22:00:00.000Z",
|
||||||
|
"until": "2026-06-03T22:00:00.000Z",
|
||||||
|
"locale": "cs",
|
||||||
|
"emptyCalendarIds": false
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"data": {
|
||||||
|
"reservations": [
|
||||||
|
{
|
||||||
|
"id": "bc275236-970f-4b88-887e-b4c5f286e3a9",
|
||||||
|
"start": "2026-06-03T08:00:00.000Z",
|
||||||
|
"end": "2026-06-03T08:45:00.000Z",
|
||||||
|
"note": null,
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"request": {
|
||||||
|
"id": "bebb68b3-f9e1-48e0-9e14-b72e5781b4c4",
|
||||||
|
"displayTitle": "Preventivní prohlídka nebo vstupní prohlídka",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "86931ca3-cfd4-4aed-af66-244cecc691ee",
|
||||||
|
"name": "Sylvie",
|
||||||
|
"surname": "Rejfířová",
|
||||||
|
"dob": "1980-06-01",
|
||||||
|
"phone": "+420602266614",
|
||||||
|
"identificationNumber": "8056010149",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 111,
|
||||||
|
"shortName": "VZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "73844dfa-316f-47da-ac3d-2554ff5aec7f",
|
||||||
|
"start": "2026-06-03T08:45:00.000Z",
|
||||||
|
"end": "2026-06-03T09:00:00.000Z",
|
||||||
|
"note": "",
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"request": {
|
||||||
|
"id": "97dd7ace-1668-479b-a09b-44d775e53227",
|
||||||
|
"displayTitle": "Kontrola INR (Quick)",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "d8c2f2b6-fdf7-462e-91de-fce908aaf3de",
|
||||||
|
"name": "Jaroslav",
|
||||||
|
"surname": "Kameník",
|
||||||
|
"dob": "1940-05-10",
|
||||||
|
"phone": "+420776702345",
|
||||||
|
"identificationNumber": "400510088",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 201,
|
||||||
|
"shortName": "VoZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c2c96faa-4129-4815-a213-ffdd887d42f8",
|
||||||
|
"start": "2026-06-03T07:00:00.000Z",
|
||||||
|
"end": "2026-06-03T07:30:00.000Z",
|
||||||
|
"note": "",
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"request": {
|
||||||
|
"id": "4ee1cee1-5ccd-425d-85b1-3896d850a784",
|
||||||
|
"displayTitle": "Prohlídka při léčbě cukrovky",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "0aeefc63-8599-4602-b731-b7c81e9106a2",
|
||||||
|
"name": "Miloslav",
|
||||||
|
"surname": "Hájek",
|
||||||
|
"dob": "1974-10-24",
|
||||||
|
"phone": "+420602262242",
|
||||||
|
"identificationNumber": "7410241014",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 207,
|
||||||
|
"shortName": "OZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "906ca466-eb83-4a65-bc2e-90020714d4e9",
|
||||||
|
"start": "2026-06-03T09:00:00.000Z",
|
||||||
|
"end": "2026-06-03T09:45:00.000Z",
|
||||||
|
"note": null,
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"request": {
|
||||||
|
"id": "6790af69-4416-4ef8-9101-7e3f7d668320",
|
||||||
|
"displayTitle": "Preventivní prohlídka nebo vstupní prohlídka",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "7bcf8cea-efe7-4f90-8e91-c8f88ba72ee6",
|
||||||
|
"name": "Denisa",
|
||||||
|
"surname": "Ryšavá",
|
||||||
|
"dob": "2007-10-24",
|
||||||
|
"phone": "+420606815415",
|
||||||
|
"identificationNumber": "0760245079",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 111,
|
||||||
|
"shortName": "VZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "a91481ba-cf7c-4968-bd54-8424565cae3d",
|
||||||
|
"start": "2026-06-03T09:45:00.000Z",
|
||||||
|
"end": "2026-06-03T09:55:00.000Z",
|
||||||
|
"note": null,
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"request": {
|
||||||
|
"id": "c0ac9fdb-5a82-4306-9d1c-ed22110205fe",
|
||||||
|
"displayTitle": "Očkování - Žloutenka A",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "ec4db98b-cce8-473c-a47e-ef24bf61d3d8",
|
||||||
|
"name": "Romana",
|
||||||
|
"surname": "Ratkiewiczová",
|
||||||
|
"dob": "1990-04-15",
|
||||||
|
"phone": "+420737261867",
|
||||||
|
"identificationNumber": "9054151128",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 201,
|
||||||
|
"shortName": "VoZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b5f01f0c-0c9f-42bb-a7bd-f0a725638d38",
|
||||||
|
"start": "2026-06-03T10:00:00.000Z",
|
||||||
|
"end": "2026-06-03T10:10:00.000Z",
|
||||||
|
"note": "",
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"request": {
|
||||||
|
"id": "48d490fa-0fd1-4a16-aba8-79f275043345",
|
||||||
|
"displayTitle": "Očkování - Žloutenka A",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "d8d36c4d-19fc-4405-9bf9-f9a733fb2dad",
|
||||||
|
"name": "Jana",
|
||||||
|
"surname": "Ptáčková",
|
||||||
|
"dob": "1947-09-17",
|
||||||
|
"phone": "+420604363791",
|
||||||
|
"identificationNumber": "475917011",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 207,
|
||||||
|
"shortName": "OZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "44d6f66b-95b9-4bfb-b2c9-69338a7cae8f",
|
||||||
|
"start": "2026-06-03T10:10:00.000Z",
|
||||||
|
"end": "2026-06-03T10:20:00.000Z",
|
||||||
|
"note": "",
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"request": {
|
||||||
|
"id": "30e1d256-eaaf-4a0b-aa13-cd511e4e309e",
|
||||||
|
"displayTitle": "Očkování - Žloutenka A",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "bb27b85a-8703-4768-86f4-2cbf4c196dd1",
|
||||||
|
"name": "Karel",
|
||||||
|
"surname": "Galus",
|
||||||
|
"dob": "1946-06-14",
|
||||||
|
"phone": "+420605230820",
|
||||||
|
"identificationNumber": "460614110",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 211,
|
||||||
|
"shortName": "ZPMV"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b128a573-849d-4bf2-9317-01142147e61e",
|
||||||
|
"start": "2026-06-03T10:30:00.000Z",
|
||||||
|
"end": "2026-06-03T10:50:00.000Z",
|
||||||
|
"note": null,
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"request": {
|
||||||
|
"id": "bbd0e36a-5148-43d2-8095-fcf746586778",
|
||||||
|
"displayTitle": "Zdravotní obtíže",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "5a0a9ff0-bbe8-4fc7-a27d-b7b475ee2189",
|
||||||
|
"name": "Lenka",
|
||||||
|
"surname": "Balousova",
|
||||||
|
"dob": "1972-03-28",
|
||||||
|
"phone": "+420603560064",
|
||||||
|
"identificationNumber": "7253282355",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 207,
|
||||||
|
"shortName": "OZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c0bbc7bc-2491-4143-a6b9-59d4fab9df63",
|
||||||
|
"start": "2026-06-03T10:50:00.000Z",
|
||||||
|
"end": "2026-06-03T11:05:00.000Z",
|
||||||
|
"note": "",
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"request": {
|
||||||
|
"id": "b0f01a56-6ae6-47fa-94bf-e693977e127b",
|
||||||
|
"displayTitle": "Zdravotní obtíže",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "3e1090b7-d0c2-4dd8-bbfe-dc464d2f1671",
|
||||||
|
"name": "Lenka",
|
||||||
|
"surname": "Vaněčková",
|
||||||
|
"dob": "1943-03-17",
|
||||||
|
"phone": "+420776599498",
|
||||||
|
"identificationNumber": "435317067",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 111,
|
||||||
|
"shortName": "VZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "9d2f969b-da52-418c-8465-d29021beab49",
|
||||||
|
"start": "2026-06-03T11:15:00.000Z",
|
||||||
|
"end": "2026-06-03T11:25:00.000Z",
|
||||||
|
"note": "",
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"request": {
|
||||||
|
"id": "019ec07d-b454-4231-9b49-9389fe675faa",
|
||||||
|
"displayTitle": "Očkování - Klíšťová encefalitida",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "865e0404-b2c8-4635-8d8d-df7a14275b14",
|
||||||
|
"name": "Jiří",
|
||||||
|
"surname": "Chomát",
|
||||||
|
"dob": "1938-03-14",
|
||||||
|
"phone": "+420737217617",
|
||||||
|
"identificationNumber": "380314026",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 111,
|
||||||
|
"shortName": "VZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"calendarIds": [
|
||||||
|
"b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"144c4e12-347c-49ca-9ec0-8ca965a4470d"
|
||||||
|
],
|
||||||
|
"clinicSlug": "mudr-buzalkova",
|
||||||
|
"since": "2026-05-29T22:00:00.000Z",
|
||||||
|
"until": "2026-05-30T21:59:59.000Z",
|
||||||
|
"locale": "cs",
|
||||||
|
"emptyCalendarIds": false
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"data": {
|
||||||
|
"reservations": [
|
||||||
|
{
|
||||||
|
"id": "afe20509-c476-48e9-83eb-fb02e161c6d8",
|
||||||
|
"start": "2026-05-30T08:00:00.000Z",
|
||||||
|
"end": "2026-05-30T08:05:00.000Z",
|
||||||
|
"note": "TEST",
|
||||||
|
"done": null,
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"request": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "aee6f9c4-1487-4934-a32a-8a7b1517271b",
|
||||||
|
"start": "2026-05-30T08:00:00.000Z",
|
||||||
|
"end": "2026-05-30T08:05:00.000Z",
|
||||||
|
"note": "TEST",
|
||||||
|
"done": null,
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"request": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c646d60b-40ca-4f32-8a11-052ab90f5d2c",
|
||||||
|
"start": "2026-05-30T07:00:00.000Z",
|
||||||
|
"end": "2026-05-30T07:05:00.000Z",
|
||||||
|
"note": "TEST poznamka z Claude Code",
|
||||||
|
"done": null,
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"request": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3ac6849a-12e2-4248-a99d-ec9a577ce820",
|
||||||
|
"start": "2026-05-30T08:00:00.000Z",
|
||||||
|
"end": "2026-05-30T08:05:00.000Z",
|
||||||
|
"note": "Test 2 z Claude Code",
|
||||||
|
"done": null,
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"request": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,295 @@
|
|||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"calendarIds": [
|
||||||
|
"b6555c7e-4e95-4657-b441-87c2c9a7b2ca"
|
||||||
|
],
|
||||||
|
"clinicSlug": "mudr-buzalkova",
|
||||||
|
"since": "2026-05-29T22:00:00.000Z",
|
||||||
|
"until": "2026-05-30T21:59:59.000Z",
|
||||||
|
"locale": "cs"
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"data": {
|
||||||
|
"reservations": [
|
||||||
|
{
|
||||||
|
"id": "afe20509-c476-48e9-83eb-fb02e161c6d8",
|
||||||
|
"start": "2026-05-30T08:00:00.000Z",
|
||||||
|
"end": "2026-05-30T08:05:00.000Z",
|
||||||
|
"note": "TEST",
|
||||||
|
"done": null,
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"request": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "aee6f9c4-1487-4934-a32a-8a7b1517271b",
|
||||||
|
"start": "2026-05-30T08:00:00.000Z",
|
||||||
|
"end": "2026-05-30T08:05:00.000Z",
|
||||||
|
"note": "TEST",
|
||||||
|
"done": null,
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"request": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c646d60b-40ca-4f32-8a11-052ab90f5d2c",
|
||||||
|
"start": "2026-05-30T07:00:00.000Z",
|
||||||
|
"end": "2026-05-30T07:05:00.000Z",
|
||||||
|
"note": "TEST poznamka z Claude Code",
|
||||||
|
"done": null,
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"request": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3ac6849a-12e2-4248-a99d-ec9a577ce820",
|
||||||
|
"start": "2026-05-30T08:00:00.000Z",
|
||||||
|
"end": "2026-05-30T08:05:00.000Z",
|
||||||
|
"note": "Test 2 z Claude Code",
|
||||||
|
"done": null,
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"request": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"recurringReservations": [
|
||||||
|
{
|
||||||
|
"recurringReservation": {
|
||||||
|
"id": "ccadcdbd-d5b3-47ec-9b18-414c6dd0d105",
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "TEST denne",
|
||||||
|
"rrule": {
|
||||||
|
"frequency": "DAILY",
|
||||||
|
"interval": 1,
|
||||||
|
"dtstart": "2026-05-30T14:40:00.000Z",
|
||||||
|
"tzid": "Europe/Prague",
|
||||||
|
"byweekday": null,
|
||||||
|
"bymonthday": null,
|
||||||
|
"byweekno": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"start": "2026-05-30T14:40:00.000Z",
|
||||||
|
"end": "2026-05-30T14:45:00.000Z",
|
||||||
|
"note": "TEST denne",
|
||||||
|
"color": "CHARCOAL"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recurringReservation": {
|
||||||
|
"id": "280cc437-2ff0-4d74-b16a-a6175d2b1020",
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "T2",
|
||||||
|
"rrule": {
|
||||||
|
"frequency": "DAILY",
|
||||||
|
"interval": 1,
|
||||||
|
"dtstart": "2026-05-30T15:35:00.000Z",
|
||||||
|
"tzid": "Europe/Prague",
|
||||||
|
"byweekday": [
|
||||||
|
"MO",
|
||||||
|
"TU",
|
||||||
|
"WE",
|
||||||
|
"TH",
|
||||||
|
"FR"
|
||||||
|
],
|
||||||
|
"bymonthday": null,
|
||||||
|
"byweekno": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instances": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recurringReservation": {
|
||||||
|
"id": "89f850f5-19dc-48b8-a24d-9173b80aa095",
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "T3",
|
||||||
|
"rrule": {
|
||||||
|
"frequency": "WEEKLY",
|
||||||
|
"interval": 1,
|
||||||
|
"dtstart": "2026-05-30T15:05:00.000Z",
|
||||||
|
"tzid": "Europe/Prague",
|
||||||
|
"byweekday": [
|
||||||
|
"SA"
|
||||||
|
],
|
||||||
|
"bymonthday": null,
|
||||||
|
"byweekno": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"start": "2026-05-30T15:05:00.000Z",
|
||||||
|
"end": "2026-05-30T15:10:00.000Z",
|
||||||
|
"note": "T3",
|
||||||
|
"color": "CHARCOAL"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recurringReservation": {
|
||||||
|
"id": "f38f7185-8050-46ee-a2c4-0ca590cc3ab9",
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "T4",
|
||||||
|
"rrule": {
|
||||||
|
"frequency": "YEARLY",
|
||||||
|
"interval": 1,
|
||||||
|
"dtstart": "2026-05-30T15:20:00.000Z",
|
||||||
|
"tzid": "Europe/Prague",
|
||||||
|
"byweekday": [
|
||||||
|
"SA"
|
||||||
|
],
|
||||||
|
"bymonthday": null,
|
||||||
|
"byweekno": [
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
5,
|
||||||
|
7,
|
||||||
|
9,
|
||||||
|
11,
|
||||||
|
13,
|
||||||
|
15,
|
||||||
|
17,
|
||||||
|
19,
|
||||||
|
21,
|
||||||
|
23,
|
||||||
|
25,
|
||||||
|
27,
|
||||||
|
29,
|
||||||
|
31,
|
||||||
|
33,
|
||||||
|
35,
|
||||||
|
37,
|
||||||
|
39,
|
||||||
|
41,
|
||||||
|
43,
|
||||||
|
45,
|
||||||
|
47,
|
||||||
|
49,
|
||||||
|
51,
|
||||||
|
53
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instances": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recurringReservation": {
|
||||||
|
"id": "357c63bc-6278-4867-acf6-e6d3124eec53",
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "T5",
|
||||||
|
"rrule": {
|
||||||
|
"frequency": "YEARLY",
|
||||||
|
"interval": 1,
|
||||||
|
"dtstart": "2026-05-30T15:35:00.000Z",
|
||||||
|
"tzid": "Europe/Prague",
|
||||||
|
"byweekday": [
|
||||||
|
"SA"
|
||||||
|
],
|
||||||
|
"bymonthday": null,
|
||||||
|
"byweekno": [
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
6,
|
||||||
|
8,
|
||||||
|
10,
|
||||||
|
12,
|
||||||
|
14,
|
||||||
|
16,
|
||||||
|
18,
|
||||||
|
20,
|
||||||
|
22,
|
||||||
|
24,
|
||||||
|
26,
|
||||||
|
28,
|
||||||
|
30,
|
||||||
|
32,
|
||||||
|
34,
|
||||||
|
36,
|
||||||
|
38,
|
||||||
|
40,
|
||||||
|
42,
|
||||||
|
44,
|
||||||
|
46,
|
||||||
|
48,
|
||||||
|
50,
|
||||||
|
52
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"start": "2026-05-30T15:35:00.000Z",
|
||||||
|
"end": "2026-05-30T15:40:00.000Z",
|
||||||
|
"note": "T5",
|
||||||
|
"color": "CHARCOAL"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recurringReservation": {
|
||||||
|
"id": "eee3904f-475d-4932-914a-fff9ada8fb6c",
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "T6",
|
||||||
|
"rrule": {
|
||||||
|
"frequency": "MONTHLY",
|
||||||
|
"interval": 1,
|
||||||
|
"dtstart": "2026-05-30T15:45:00.000Z",
|
||||||
|
"tzid": "Europe/Prague",
|
||||||
|
"byweekday": null,
|
||||||
|
"bymonthday": [
|
||||||
|
30
|
||||||
|
],
|
||||||
|
"byweekno": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"start": "2026-05-30T15:45:00.000Z",
|
||||||
|
"end": "2026-05-30T15:50:00.000Z",
|
||||||
|
"note": "T6",
|
||||||
|
"color": "CHARCOAL"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recurringReservation": {
|
||||||
|
"id": "95c5c675-68a2-4181-9d6d-1ebc6d2e6a4c",
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "T7",
|
||||||
|
"rrule": {
|
||||||
|
"frequency": "MONTHLY",
|
||||||
|
"interval": 1,
|
||||||
|
"dtstart": "2026-05-30T15:20:00.000Z",
|
||||||
|
"tzid": "Europe/Prague",
|
||||||
|
"byweekday": [
|
||||||
|
"-1SA"
|
||||||
|
],
|
||||||
|
"bymonthday": null,
|
||||||
|
"byweekno": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"start": "2026-05-30T15:20:00.000Z",
|
||||||
|
"end": "2026-05-30T15:25:00.000Z",
|
||||||
|
"note": "T7",
|
||||||
|
"color": "CHARCOAL"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,232 @@
|
|||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"calendarIds": [
|
||||||
|
"b6555c7e-4e95-4657-b441-87c2c9a7b2ca"
|
||||||
|
],
|
||||||
|
"clinicSlug": "mudr-buzalkova",
|
||||||
|
"since": "2026-05-29T22:00:00.000Z",
|
||||||
|
"until": "2026-05-30T21:59:59.000Z",
|
||||||
|
"locale": "cs"
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"data": {
|
||||||
|
"reservations": [
|
||||||
|
{
|
||||||
|
"id": "afe20509-c476-48e9-83eb-fb02e161c6d8",
|
||||||
|
"start": "2026-05-30T08:00:00.000Z",
|
||||||
|
"end": "2026-05-30T08:05:00.000Z",
|
||||||
|
"note": "TEST",
|
||||||
|
"done": null,
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"request": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "aee6f9c4-1487-4934-a32a-8a7b1517271b",
|
||||||
|
"start": "2026-05-30T08:00:00.000Z",
|
||||||
|
"end": "2026-05-30T08:05:00.000Z",
|
||||||
|
"note": "TEST",
|
||||||
|
"done": null,
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"request": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3ac6849a-12e2-4248-a99d-ec9a577ce820",
|
||||||
|
"start": "2026-05-30T08:00:00.000Z",
|
||||||
|
"end": "2026-05-30T08:05:00.000Z",
|
||||||
|
"note": "Test 2 z Claude Code",
|
||||||
|
"done": null,
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"request": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"recurringReservations": [
|
||||||
|
{
|
||||||
|
"recurringReservation": {
|
||||||
|
"id": "280cc437-2ff0-4d74-b16a-a6175d2b1020",
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "T2",
|
||||||
|
"rrule": {
|
||||||
|
"frequency": "DAILY",
|
||||||
|
"interval": 1,
|
||||||
|
"dtstart": "2026-05-30T15:35:00.000Z",
|
||||||
|
"tzid": "Europe/Prague",
|
||||||
|
"byweekday": [
|
||||||
|
"MO",
|
||||||
|
"TU",
|
||||||
|
"WE",
|
||||||
|
"TH",
|
||||||
|
"FR"
|
||||||
|
],
|
||||||
|
"bymonthday": null,
|
||||||
|
"byweekno": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instances": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recurringReservation": {
|
||||||
|
"id": "f38f7185-8050-46ee-a2c4-0ca590cc3ab9",
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "T4",
|
||||||
|
"rrule": {
|
||||||
|
"frequency": "YEARLY",
|
||||||
|
"interval": 1,
|
||||||
|
"dtstart": "2026-05-30T15:20:00.000Z",
|
||||||
|
"tzid": "Europe/Prague",
|
||||||
|
"byweekday": [
|
||||||
|
"SA"
|
||||||
|
],
|
||||||
|
"bymonthday": null,
|
||||||
|
"byweekno": [
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
5,
|
||||||
|
7,
|
||||||
|
9,
|
||||||
|
11,
|
||||||
|
13,
|
||||||
|
15,
|
||||||
|
17,
|
||||||
|
19,
|
||||||
|
21,
|
||||||
|
23,
|
||||||
|
25,
|
||||||
|
27,
|
||||||
|
29,
|
||||||
|
31,
|
||||||
|
33,
|
||||||
|
35,
|
||||||
|
37,
|
||||||
|
39,
|
||||||
|
41,
|
||||||
|
43,
|
||||||
|
45,
|
||||||
|
47,
|
||||||
|
49,
|
||||||
|
51,
|
||||||
|
53
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instances": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recurringReservation": {
|
||||||
|
"id": "357c63bc-6278-4867-acf6-e6d3124eec53",
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "T5",
|
||||||
|
"rrule": {
|
||||||
|
"frequency": "YEARLY",
|
||||||
|
"interval": 1,
|
||||||
|
"dtstart": "2026-05-30T15:35:00.000Z",
|
||||||
|
"tzid": "Europe/Prague",
|
||||||
|
"byweekday": [
|
||||||
|
"SA"
|
||||||
|
],
|
||||||
|
"bymonthday": null,
|
||||||
|
"byweekno": [
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
6,
|
||||||
|
8,
|
||||||
|
10,
|
||||||
|
12,
|
||||||
|
14,
|
||||||
|
16,
|
||||||
|
18,
|
||||||
|
20,
|
||||||
|
22,
|
||||||
|
24,
|
||||||
|
26,
|
||||||
|
28,
|
||||||
|
30,
|
||||||
|
32,
|
||||||
|
34,
|
||||||
|
36,
|
||||||
|
38,
|
||||||
|
40,
|
||||||
|
42,
|
||||||
|
44,
|
||||||
|
46,
|
||||||
|
48,
|
||||||
|
50,
|
||||||
|
52
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"start": "2026-05-30T15:35:00.000Z",
|
||||||
|
"end": "2026-05-30T15:40:00.000Z",
|
||||||
|
"note": "T5",
|
||||||
|
"color": "CHARCOAL"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recurringReservation": {
|
||||||
|
"id": "eee3904f-475d-4932-914a-fff9ada8fb6c",
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "T6",
|
||||||
|
"rrule": {
|
||||||
|
"frequency": "MONTHLY",
|
||||||
|
"interval": 1,
|
||||||
|
"dtstart": "2026-05-30T15:45:00.000Z",
|
||||||
|
"tzid": "Europe/Prague",
|
||||||
|
"byweekday": null,
|
||||||
|
"bymonthday": [
|
||||||
|
30
|
||||||
|
],
|
||||||
|
"byweekno": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"start": "2026-05-30T15:45:00.000Z",
|
||||||
|
"end": "2026-05-30T15:50:00.000Z",
|
||||||
|
"note": "T6",
|
||||||
|
"color": "CHARCOAL"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recurringReservation": {
|
||||||
|
"id": "95c5c675-68a2-4181-9d6d-1ebc6d2e6a4c",
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "T7",
|
||||||
|
"rrule": {
|
||||||
|
"frequency": "MONTHLY",
|
||||||
|
"interval": 1,
|
||||||
|
"dtstart": "2026-05-30T15:20:00.000Z",
|
||||||
|
"tzid": "Europe/Prague",
|
||||||
|
"byweekday": [
|
||||||
|
"-1SA"
|
||||||
|
],
|
||||||
|
"bymonthday": null,
|
||||||
|
"byweekno": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"start": "2026-05-30T15:20:00.000Z",
|
||||||
|
"end": "2026-05-30T15:25:00.000Z",
|
||||||
|
"note": "T7",
|
||||||
|
"color": "CHARCOAL"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"calendarIds": [
|
||||||
|
"b6555c7e-4e95-4657-b441-87c2c9a7b2ca"
|
||||||
|
],
|
||||||
|
"clinicSlug": "mudr-buzalkova",
|
||||||
|
"since": "2026-05-30T22:00:00.000Z",
|
||||||
|
"until": "2026-05-31T21:59:59.000Z",
|
||||||
|
"locale": "cs",
|
||||||
|
"emptyCalendarIds": false
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"data": {
|
||||||
|
"reservations": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,247 @@
|
|||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"calendarIds": [
|
||||||
|
"b6555c7e-4e95-4657-b441-87c2c9a7b2ca"
|
||||||
|
],
|
||||||
|
"clinicSlug": "mudr-buzalkova",
|
||||||
|
"since": "2026-05-30T22:00:00.000Z",
|
||||||
|
"until": "2026-05-31T21:59:59.000Z",
|
||||||
|
"locale": "cs"
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"data": {
|
||||||
|
"reservations": [],
|
||||||
|
"recurringReservations": [
|
||||||
|
{
|
||||||
|
"recurringReservation": {
|
||||||
|
"id": "ccadcdbd-d5b3-47ec-9b18-414c6dd0d105",
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "TEST denne",
|
||||||
|
"rrule": {
|
||||||
|
"frequency": "DAILY",
|
||||||
|
"interval": 1,
|
||||||
|
"dtstart": "2026-05-30T14:40:00.000Z",
|
||||||
|
"tzid": "Europe/Prague",
|
||||||
|
"byweekday": null,
|
||||||
|
"bymonthday": null,
|
||||||
|
"byweekno": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"start": "2026-05-31T14:40:00.000Z",
|
||||||
|
"end": "2026-05-31T14:45:00.000Z",
|
||||||
|
"note": "TEST denne",
|
||||||
|
"color": "CHARCOAL"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recurringReservation": {
|
||||||
|
"id": "280cc437-2ff0-4d74-b16a-a6175d2b1020",
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "T2",
|
||||||
|
"rrule": {
|
||||||
|
"frequency": "DAILY",
|
||||||
|
"interval": 1,
|
||||||
|
"dtstart": "2026-05-30T15:35:00.000Z",
|
||||||
|
"tzid": "Europe/Prague",
|
||||||
|
"byweekday": [
|
||||||
|
"MO",
|
||||||
|
"TU",
|
||||||
|
"WE",
|
||||||
|
"TH",
|
||||||
|
"FR"
|
||||||
|
],
|
||||||
|
"bymonthday": null,
|
||||||
|
"byweekno": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instances": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recurringReservation": {
|
||||||
|
"id": "89f850f5-19dc-48b8-a24d-9173b80aa095",
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "T3",
|
||||||
|
"rrule": {
|
||||||
|
"frequency": "WEEKLY",
|
||||||
|
"interval": 1,
|
||||||
|
"dtstart": "2026-05-30T15:05:00.000Z",
|
||||||
|
"tzid": "Europe/Prague",
|
||||||
|
"byweekday": [
|
||||||
|
"SA"
|
||||||
|
],
|
||||||
|
"bymonthday": null,
|
||||||
|
"byweekno": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instances": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recurringReservation": {
|
||||||
|
"id": "f38f7185-8050-46ee-a2c4-0ca590cc3ab9",
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "T4",
|
||||||
|
"rrule": {
|
||||||
|
"frequency": "YEARLY",
|
||||||
|
"interval": 1,
|
||||||
|
"dtstart": "2026-05-30T15:20:00.000Z",
|
||||||
|
"tzid": "Europe/Prague",
|
||||||
|
"byweekday": [
|
||||||
|
"SA"
|
||||||
|
],
|
||||||
|
"bymonthday": null,
|
||||||
|
"byweekno": [
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
5,
|
||||||
|
7,
|
||||||
|
9,
|
||||||
|
11,
|
||||||
|
13,
|
||||||
|
15,
|
||||||
|
17,
|
||||||
|
19,
|
||||||
|
21,
|
||||||
|
23,
|
||||||
|
25,
|
||||||
|
27,
|
||||||
|
29,
|
||||||
|
31,
|
||||||
|
33,
|
||||||
|
35,
|
||||||
|
37,
|
||||||
|
39,
|
||||||
|
41,
|
||||||
|
43,
|
||||||
|
45,
|
||||||
|
47,
|
||||||
|
49,
|
||||||
|
51,
|
||||||
|
53
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instances": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recurringReservation": {
|
||||||
|
"id": "357c63bc-6278-4867-acf6-e6d3124eec53",
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "T5",
|
||||||
|
"rrule": {
|
||||||
|
"frequency": "YEARLY",
|
||||||
|
"interval": 1,
|
||||||
|
"dtstart": "2026-05-30T15:35:00.000Z",
|
||||||
|
"tzid": "Europe/Prague",
|
||||||
|
"byweekday": [
|
||||||
|
"SA"
|
||||||
|
],
|
||||||
|
"bymonthday": null,
|
||||||
|
"byweekno": [
|
||||||
|
2,
|
||||||
|
4,
|
||||||
|
6,
|
||||||
|
8,
|
||||||
|
10,
|
||||||
|
12,
|
||||||
|
14,
|
||||||
|
16,
|
||||||
|
18,
|
||||||
|
20,
|
||||||
|
22,
|
||||||
|
24,
|
||||||
|
26,
|
||||||
|
28,
|
||||||
|
30,
|
||||||
|
32,
|
||||||
|
34,
|
||||||
|
36,
|
||||||
|
38,
|
||||||
|
40,
|
||||||
|
42,
|
||||||
|
44,
|
||||||
|
46,
|
||||||
|
48,
|
||||||
|
50,
|
||||||
|
52
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instances": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recurringReservation": {
|
||||||
|
"id": "eee3904f-475d-4932-914a-fff9ada8fb6c",
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "T6",
|
||||||
|
"rrule": {
|
||||||
|
"frequency": "MONTHLY",
|
||||||
|
"interval": 1,
|
||||||
|
"dtstart": "2026-05-30T15:45:00.000Z",
|
||||||
|
"tzid": "Europe/Prague",
|
||||||
|
"byweekday": null,
|
||||||
|
"bymonthday": [
|
||||||
|
30
|
||||||
|
],
|
||||||
|
"byweekno": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instances": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recurringReservation": {
|
||||||
|
"id": "95c5c675-68a2-4181-9d6d-1ebc6d2e6a4c",
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "T7",
|
||||||
|
"rrule": {
|
||||||
|
"frequency": "MONTHLY",
|
||||||
|
"interval": 1,
|
||||||
|
"dtstart": "2026-05-30T15:20:00.000Z",
|
||||||
|
"tzid": "Europe/Prague",
|
||||||
|
"byweekday": [
|
||||||
|
"-1SA"
|
||||||
|
],
|
||||||
|
"bymonthday": null,
|
||||||
|
"byweekno": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instances": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recurringReservation": {
|
||||||
|
"id": "f675ca4f-1169-4b3b-8266-b171d23849c8",
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "T8",
|
||||||
|
"rrule": {
|
||||||
|
"frequency": "YEARLY",
|
||||||
|
"interval": 1,
|
||||||
|
"dtstart": "2026-05-31T15:05:00.000Z",
|
||||||
|
"tzid": "Europe/Prague",
|
||||||
|
"byweekday": null,
|
||||||
|
"bymonthday": null,
|
||||||
|
"byweekno": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instances": [
|
||||||
|
{
|
||||||
|
"start": "2026-05-31T15:05:00.000Z",
|
||||||
|
"end": "2026-05-31T15:10:00.000Z",
|
||||||
|
"note": "T8",
|
||||||
|
"color": "CHARCOAL"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,278 @@
|
|||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"calendarIds": [
|
||||||
|
"144c4e12-347c-49ca-9ec0-8ca965a4470d"
|
||||||
|
],
|
||||||
|
"clinicSlug": "mudr-buzalkova",
|
||||||
|
"since": "2026-06-02T22:00:00.000Z",
|
||||||
|
"until": "2026-06-03T21:59:59.000Z",
|
||||||
|
"locale": "cs",
|
||||||
|
"emptyCalendarIds": false
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"data": {
|
||||||
|
"reservations": [
|
||||||
|
{
|
||||||
|
"id": "bc275236-970f-4b88-887e-b4c5f286e3a9",
|
||||||
|
"start": "2026-06-03T08:00:00.000Z",
|
||||||
|
"end": "2026-06-03T08:45:00.000Z",
|
||||||
|
"note": null,
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "144c4e12-347c-49ca-9ec0-8ca965a4470d",
|
||||||
|
"request": {
|
||||||
|
"id": "bebb68b3-f9e1-48e0-9e14-b72e5781b4c4",
|
||||||
|
"displayTitle": "Preventivní prohlídka nebo vstupní prohlídka",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "86931ca3-cfd4-4aed-af66-244cecc691ee",
|
||||||
|
"name": "Sylvie",
|
||||||
|
"surname": "Rejfířová",
|
||||||
|
"dob": "1980-06-01",
|
||||||
|
"phone": "+420602266614",
|
||||||
|
"identificationNumber": "8056010149",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 111,
|
||||||
|
"shortName": "VZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "73844dfa-316f-47da-ac3d-2554ff5aec7f",
|
||||||
|
"start": "2026-06-03T08:45:00.000Z",
|
||||||
|
"end": "2026-06-03T09:00:00.000Z",
|
||||||
|
"note": "",
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "144c4e12-347c-49ca-9ec0-8ca965a4470d",
|
||||||
|
"request": {
|
||||||
|
"id": "97dd7ace-1668-479b-a09b-44d775e53227",
|
||||||
|
"displayTitle": "Kontrola INR (Quick)",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "d8c2f2b6-fdf7-462e-91de-fce908aaf3de",
|
||||||
|
"name": "Jaroslav",
|
||||||
|
"surname": "Kameník",
|
||||||
|
"dob": "1940-05-10",
|
||||||
|
"phone": "+420776702345",
|
||||||
|
"identificationNumber": "400510088",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 201,
|
||||||
|
"shortName": "VoZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c2c96faa-4129-4815-a213-ffdd887d42f8",
|
||||||
|
"start": "2026-06-03T07:00:00.000Z",
|
||||||
|
"end": "2026-06-03T07:30:00.000Z",
|
||||||
|
"note": "",
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "144c4e12-347c-49ca-9ec0-8ca965a4470d",
|
||||||
|
"request": {
|
||||||
|
"id": "4ee1cee1-5ccd-425d-85b1-3896d850a784",
|
||||||
|
"displayTitle": "Prohlídka při léčbě cukrovky",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "0aeefc63-8599-4602-b731-b7c81e9106a2",
|
||||||
|
"name": "Miloslav",
|
||||||
|
"surname": "Hájek",
|
||||||
|
"dob": "1974-10-24",
|
||||||
|
"phone": "+420602262242",
|
||||||
|
"identificationNumber": "7410241014",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 207,
|
||||||
|
"shortName": "OZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "906ca466-eb83-4a65-bc2e-90020714d4e9",
|
||||||
|
"start": "2026-06-03T09:00:00.000Z",
|
||||||
|
"end": "2026-06-03T09:45:00.000Z",
|
||||||
|
"note": null,
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "144c4e12-347c-49ca-9ec0-8ca965a4470d",
|
||||||
|
"request": {
|
||||||
|
"id": "6790af69-4416-4ef8-9101-7e3f7d668320",
|
||||||
|
"displayTitle": "Preventivní prohlídka nebo vstupní prohlídka",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "7bcf8cea-efe7-4f90-8e91-c8f88ba72ee6",
|
||||||
|
"name": "Denisa",
|
||||||
|
"surname": "Ryšavá",
|
||||||
|
"dob": "2007-10-24",
|
||||||
|
"phone": "+420606815415",
|
||||||
|
"identificationNumber": "0760245079",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 111,
|
||||||
|
"shortName": "VZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "a91481ba-cf7c-4968-bd54-8424565cae3d",
|
||||||
|
"start": "2026-06-03T09:45:00.000Z",
|
||||||
|
"end": "2026-06-03T09:55:00.000Z",
|
||||||
|
"note": null,
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "144c4e12-347c-49ca-9ec0-8ca965a4470d",
|
||||||
|
"request": {
|
||||||
|
"id": "c0ac9fdb-5a82-4306-9d1c-ed22110205fe",
|
||||||
|
"displayTitle": "Očkování - Žloutenka A",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "ec4db98b-cce8-473c-a47e-ef24bf61d3d8",
|
||||||
|
"name": "Romana",
|
||||||
|
"surname": "Ratkiewiczová",
|
||||||
|
"dob": "1990-04-15",
|
||||||
|
"phone": "+420737261867",
|
||||||
|
"identificationNumber": "9054151128",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 201,
|
||||||
|
"shortName": "VoZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b5f01f0c-0c9f-42bb-a7bd-f0a725638d38",
|
||||||
|
"start": "2026-06-03T10:00:00.000Z",
|
||||||
|
"end": "2026-06-03T10:10:00.000Z",
|
||||||
|
"note": "",
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "144c4e12-347c-49ca-9ec0-8ca965a4470d",
|
||||||
|
"request": {
|
||||||
|
"id": "48d490fa-0fd1-4a16-aba8-79f275043345",
|
||||||
|
"displayTitle": "Očkování - Žloutenka A",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "d8d36c4d-19fc-4405-9bf9-f9a733fb2dad",
|
||||||
|
"name": "Jana",
|
||||||
|
"surname": "Ptáčková",
|
||||||
|
"dob": "1947-09-17",
|
||||||
|
"phone": "+420604363791",
|
||||||
|
"identificationNumber": "475917011",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 207,
|
||||||
|
"shortName": "OZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "44d6f66b-95b9-4bfb-b2c9-69338a7cae8f",
|
||||||
|
"start": "2026-06-03T10:10:00.000Z",
|
||||||
|
"end": "2026-06-03T10:20:00.000Z",
|
||||||
|
"note": "",
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "144c4e12-347c-49ca-9ec0-8ca965a4470d",
|
||||||
|
"request": {
|
||||||
|
"id": "30e1d256-eaaf-4a0b-aa13-cd511e4e309e",
|
||||||
|
"displayTitle": "Očkování - Žloutenka A",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "bb27b85a-8703-4768-86f4-2cbf4c196dd1",
|
||||||
|
"name": "Karel",
|
||||||
|
"surname": "Galus",
|
||||||
|
"dob": "1946-06-14",
|
||||||
|
"phone": "+420605230820",
|
||||||
|
"identificationNumber": "460614110",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 211,
|
||||||
|
"shortName": "ZPMV"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b128a573-849d-4bf2-9317-01142147e61e",
|
||||||
|
"start": "2026-06-03T10:30:00.000Z",
|
||||||
|
"end": "2026-06-03T10:50:00.000Z",
|
||||||
|
"note": null,
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "144c4e12-347c-49ca-9ec0-8ca965a4470d",
|
||||||
|
"request": {
|
||||||
|
"id": "bbd0e36a-5148-43d2-8095-fcf746586778",
|
||||||
|
"displayTitle": "Zdravotní obtíže",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "5a0a9ff0-bbe8-4fc7-a27d-b7b475ee2189",
|
||||||
|
"name": "Lenka",
|
||||||
|
"surname": "Balousova",
|
||||||
|
"dob": "1972-03-28",
|
||||||
|
"phone": "+420603560064",
|
||||||
|
"identificationNumber": "7253282355",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 207,
|
||||||
|
"shortName": "OZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c0bbc7bc-2491-4143-a6b9-59d4fab9df63",
|
||||||
|
"start": "2026-06-03T10:50:00.000Z",
|
||||||
|
"end": "2026-06-03T11:05:00.000Z",
|
||||||
|
"note": "",
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "144c4e12-347c-49ca-9ec0-8ca965a4470d",
|
||||||
|
"request": {
|
||||||
|
"id": "b0f01a56-6ae6-47fa-94bf-e693977e127b",
|
||||||
|
"displayTitle": "Zdravotní obtíže",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "3e1090b7-d0c2-4dd8-bbfe-dc464d2f1671",
|
||||||
|
"name": "Lenka",
|
||||||
|
"surname": "Vaněčková",
|
||||||
|
"dob": "1943-03-17",
|
||||||
|
"phone": "+420776599498",
|
||||||
|
"identificationNumber": "435317067",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 111,
|
||||||
|
"shortName": "VZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "9d2f969b-da52-418c-8465-d29021beab49",
|
||||||
|
"start": "2026-06-03T11:15:00.000Z",
|
||||||
|
"end": "2026-06-03T11:25:00.000Z",
|
||||||
|
"note": "",
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "144c4e12-347c-49ca-9ec0-8ca965a4470d",
|
||||||
|
"request": {
|
||||||
|
"id": "019ec07d-b454-4231-9b49-9389fe675faa",
|
||||||
|
"displayTitle": "Očkování - Klíšťová encefalitida",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "865e0404-b2c8-4635-8d8d-df7a14275b14",
|
||||||
|
"name": "Jiří",
|
||||||
|
"surname": "Chomát",
|
||||||
|
"dob": "1938-03-14",
|
||||||
|
"phone": "+420737217617",
|
||||||
|
"identificationNumber": "380314026",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 111,
|
||||||
|
"shortName": "VZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,278 @@
|
|||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"calendarIds": [
|
||||||
|
"144c4e12-347c-49ca-9ec0-8ca965a4470d"
|
||||||
|
],
|
||||||
|
"clinicSlug": "mudr-buzalkova",
|
||||||
|
"since": "2026-06-02T22:00:00.000Z",
|
||||||
|
"until": "2026-06-03T21:59:59.000Z",
|
||||||
|
"locale": "cs"
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"data": {
|
||||||
|
"reservations": [
|
||||||
|
{
|
||||||
|
"id": "bc275236-970f-4b88-887e-b4c5f286e3a9",
|
||||||
|
"start": "2026-06-03T08:00:00.000Z",
|
||||||
|
"end": "2026-06-03T08:45:00.000Z",
|
||||||
|
"note": null,
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "144c4e12-347c-49ca-9ec0-8ca965a4470d",
|
||||||
|
"request": {
|
||||||
|
"id": "bebb68b3-f9e1-48e0-9e14-b72e5781b4c4",
|
||||||
|
"displayTitle": "Preventivní prohlídka nebo vstupní prohlídka",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "86931ca3-cfd4-4aed-af66-244cecc691ee",
|
||||||
|
"name": "Sylvie",
|
||||||
|
"surname": "Rejfířová",
|
||||||
|
"dob": "1980-06-01",
|
||||||
|
"phone": "+420602266614",
|
||||||
|
"identificationNumber": "8056010149",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 111,
|
||||||
|
"shortName": "VZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "73844dfa-316f-47da-ac3d-2554ff5aec7f",
|
||||||
|
"start": "2026-06-03T08:45:00.000Z",
|
||||||
|
"end": "2026-06-03T09:00:00.000Z",
|
||||||
|
"note": "",
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "144c4e12-347c-49ca-9ec0-8ca965a4470d",
|
||||||
|
"request": {
|
||||||
|
"id": "97dd7ace-1668-479b-a09b-44d775e53227",
|
||||||
|
"displayTitle": "Kontrola INR (Quick)",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "d8c2f2b6-fdf7-462e-91de-fce908aaf3de",
|
||||||
|
"name": "Jaroslav",
|
||||||
|
"surname": "Kameník",
|
||||||
|
"dob": "1940-05-10",
|
||||||
|
"phone": "+420776702345",
|
||||||
|
"identificationNumber": "400510088",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 201,
|
||||||
|
"shortName": "VoZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c2c96faa-4129-4815-a213-ffdd887d42f8",
|
||||||
|
"start": "2026-06-03T07:00:00.000Z",
|
||||||
|
"end": "2026-06-03T07:30:00.000Z",
|
||||||
|
"note": "",
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "144c4e12-347c-49ca-9ec0-8ca965a4470d",
|
||||||
|
"request": {
|
||||||
|
"id": "4ee1cee1-5ccd-425d-85b1-3896d850a784",
|
||||||
|
"displayTitle": "Prohlídka při léčbě cukrovky",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "0aeefc63-8599-4602-b731-b7c81e9106a2",
|
||||||
|
"name": "Miloslav",
|
||||||
|
"surname": "Hájek",
|
||||||
|
"dob": "1974-10-24",
|
||||||
|
"phone": "+420602262242",
|
||||||
|
"identificationNumber": "7410241014",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 207,
|
||||||
|
"shortName": "OZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "906ca466-eb83-4a65-bc2e-90020714d4e9",
|
||||||
|
"start": "2026-06-03T09:00:00.000Z",
|
||||||
|
"end": "2026-06-03T09:45:00.000Z",
|
||||||
|
"note": null,
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "144c4e12-347c-49ca-9ec0-8ca965a4470d",
|
||||||
|
"request": {
|
||||||
|
"id": "6790af69-4416-4ef8-9101-7e3f7d668320",
|
||||||
|
"displayTitle": "Preventivní prohlídka nebo vstupní prohlídka",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "7bcf8cea-efe7-4f90-8e91-c8f88ba72ee6",
|
||||||
|
"name": "Denisa",
|
||||||
|
"surname": "Ryšavá",
|
||||||
|
"dob": "2007-10-24",
|
||||||
|
"phone": "+420606815415",
|
||||||
|
"identificationNumber": "0760245079",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 111,
|
||||||
|
"shortName": "VZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "a91481ba-cf7c-4968-bd54-8424565cae3d",
|
||||||
|
"start": "2026-06-03T09:45:00.000Z",
|
||||||
|
"end": "2026-06-03T09:55:00.000Z",
|
||||||
|
"note": null,
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "144c4e12-347c-49ca-9ec0-8ca965a4470d",
|
||||||
|
"request": {
|
||||||
|
"id": "c0ac9fdb-5a82-4306-9d1c-ed22110205fe",
|
||||||
|
"displayTitle": "Očkování - Žloutenka A",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "ec4db98b-cce8-473c-a47e-ef24bf61d3d8",
|
||||||
|
"name": "Romana",
|
||||||
|
"surname": "Ratkiewiczová",
|
||||||
|
"dob": "1990-04-15",
|
||||||
|
"phone": "+420737261867",
|
||||||
|
"identificationNumber": "9054151128",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 201,
|
||||||
|
"shortName": "VoZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b5f01f0c-0c9f-42bb-a7bd-f0a725638d38",
|
||||||
|
"start": "2026-06-03T10:00:00.000Z",
|
||||||
|
"end": "2026-06-03T10:10:00.000Z",
|
||||||
|
"note": "",
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "144c4e12-347c-49ca-9ec0-8ca965a4470d",
|
||||||
|
"request": {
|
||||||
|
"id": "48d490fa-0fd1-4a16-aba8-79f275043345",
|
||||||
|
"displayTitle": "Očkování - Žloutenka A",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "d8d36c4d-19fc-4405-9bf9-f9a733fb2dad",
|
||||||
|
"name": "Jana",
|
||||||
|
"surname": "Ptáčková",
|
||||||
|
"dob": "1947-09-17",
|
||||||
|
"phone": "+420604363791",
|
||||||
|
"identificationNumber": "475917011",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 207,
|
||||||
|
"shortName": "OZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "44d6f66b-95b9-4bfb-b2c9-69338a7cae8f",
|
||||||
|
"start": "2026-06-03T10:10:00.000Z",
|
||||||
|
"end": "2026-06-03T10:20:00.000Z",
|
||||||
|
"note": "",
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "144c4e12-347c-49ca-9ec0-8ca965a4470d",
|
||||||
|
"request": {
|
||||||
|
"id": "30e1d256-eaaf-4a0b-aa13-cd511e4e309e",
|
||||||
|
"displayTitle": "Očkování - Žloutenka A",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "bb27b85a-8703-4768-86f4-2cbf4c196dd1",
|
||||||
|
"name": "Karel",
|
||||||
|
"surname": "Galus",
|
||||||
|
"dob": "1946-06-14",
|
||||||
|
"phone": "+420605230820",
|
||||||
|
"identificationNumber": "460614110",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 211,
|
||||||
|
"shortName": "ZPMV"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b128a573-849d-4bf2-9317-01142147e61e",
|
||||||
|
"start": "2026-06-03T10:30:00.000Z",
|
||||||
|
"end": "2026-06-03T10:50:00.000Z",
|
||||||
|
"note": null,
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "144c4e12-347c-49ca-9ec0-8ca965a4470d",
|
||||||
|
"request": {
|
||||||
|
"id": "bbd0e36a-5148-43d2-8095-fcf746586778",
|
||||||
|
"displayTitle": "Zdravotní obtíže",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "5a0a9ff0-bbe8-4fc7-a27d-b7b475ee2189",
|
||||||
|
"name": "Lenka",
|
||||||
|
"surname": "Balousova",
|
||||||
|
"dob": "1972-03-28",
|
||||||
|
"phone": "+420603560064",
|
||||||
|
"identificationNumber": "7253282355",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 207,
|
||||||
|
"shortName": "OZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c0bbc7bc-2491-4143-a6b9-59d4fab9df63",
|
||||||
|
"start": "2026-06-03T10:50:00.000Z",
|
||||||
|
"end": "2026-06-03T11:05:00.000Z",
|
||||||
|
"note": "",
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "144c4e12-347c-49ca-9ec0-8ca965a4470d",
|
||||||
|
"request": {
|
||||||
|
"id": "b0f01a56-6ae6-47fa-94bf-e693977e127b",
|
||||||
|
"displayTitle": "Zdravotní obtíže",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "3e1090b7-d0c2-4dd8-bbfe-dc464d2f1671",
|
||||||
|
"name": "Lenka",
|
||||||
|
"surname": "Vaněčková",
|
||||||
|
"dob": "1943-03-17",
|
||||||
|
"phone": "+420776599498",
|
||||||
|
"identificationNumber": "435317067",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 111,
|
||||||
|
"shortName": "VZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "9d2f969b-da52-418c-8465-d29021beab49",
|
||||||
|
"start": "2026-06-03T11:15:00.000Z",
|
||||||
|
"end": "2026-06-03T11:25:00.000Z",
|
||||||
|
"note": "",
|
||||||
|
"done": null,
|
||||||
|
"color": null,
|
||||||
|
"canceledAt": null,
|
||||||
|
"calendarId": "144c4e12-347c-49ca-9ec0-8ca965a4470d",
|
||||||
|
"request": {
|
||||||
|
"id": "019ec07d-b454-4231-9b49-9389fe675faa",
|
||||||
|
"displayTitle": "Očkování - Klíšťová encefalitida",
|
||||||
|
"extendedPatient": {
|
||||||
|
"id": "865e0404-b2c8-4635-8d8d-df7a14275b14",
|
||||||
|
"name": "Jiří",
|
||||||
|
"surname": "Chomát",
|
||||||
|
"dob": "1938-03-14",
|
||||||
|
"phone": "+420737217617",
|
||||||
|
"identificationNumber": "380314026",
|
||||||
|
"insuranceCompanyObject": {
|
||||||
|
"code": 111,
|
||||||
|
"shortName": "VZP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"recurringReservations": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"clinicSlug": "mudr-buzalkova",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "TEST poznamka z Claude Code",
|
||||||
|
"timeSlotInput": {
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"start": "2026-05-30T07:00:00.000Z",
|
||||||
|
"end": "2026-05-30T07:05:00.000Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"data": {
|
||||||
|
"reservation": {
|
||||||
|
"id": "c646d60b-40ca-4f32-8a11-052ab90f5d2c",
|
||||||
|
"__typename": "Reservation"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"request": {
|
||||||
|
"clinicSlug": "mudr-buzalkova",
|
||||||
|
"color": "CHARCOAL",
|
||||||
|
"note": "Test 2 z Claude Code",
|
||||||
|
"timeSlotInput": {
|
||||||
|
"calendarId": "b6555c7e-4e95-4657-b441-87c2c9a7b2ca",
|
||||||
|
"start": "2026-05-30T08:00:00.000Z",
|
||||||
|
"end": "2026-05-30T08:05:00.000Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"data": {
|
||||||
|
"reservation": {
|
||||||
|
"id": "3ac6849a-12e2-4248-a99d-ec9a577ce820",
|
||||||
|
"__typename": "Reservation"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Smazani rezervace / poznamky v Medevio kalendari.
|
||||||
|
|
||||||
|
Defaultni chovani:
|
||||||
|
- jednorazova: smazat (cancel)
|
||||||
|
- opakujici se: smazat tuto a nasledujici (ThisAndFuture)
|
||||||
|
|
||||||
|
Pouziti jako modul:
|
||||||
|
from smaz_poznamku import smaz_jednorazovou, smaz_opakujici
|
||||||
|
|
||||||
|
smaz_jednorazovou("<reservation_uuid>")
|
||||||
|
smaz_opakujici("<recurring_id>", date="2026-05-30T14:40:00.000Z") # default ThisAndFuture
|
||||||
|
smaz_opakujici("<recurring_id>", date="...Z", update_type="All")
|
||||||
|
smaz_opakujici("<recurring_id>", date="...Z", update_type="Single")
|
||||||
|
|
||||||
|
CLI:
|
||||||
|
python smaz_poznamku.py --jednorazova <reservation_uuid>
|
||||||
|
python smaz_poznamku.py --opakujici <recurring_id> --datum 2026-05-30T14:40:00.000Z
|
||||||
|
python smaz_poznamku.py --opakujici <id> --datum ...Z --typ All
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import argparse
|
||||||
|
from pathlib import Path
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from dateutil import parser as dtparser, 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")
|
||||||
|
|
||||||
|
BASE_DIR = Path(__file__).resolve().parent
|
||||||
|
TOKEN_PATH = BASE_DIR / "token.txt"
|
||||||
|
DEBUG_DIR = BASE_DIR / "debug"
|
||||||
|
|
||||||
|
VALID_UPDATE_TYPES = ("Single", "ThisAndFuture", "All")
|
||||||
|
|
||||||
|
MUTATION_SINGLE = """mutation UpdateReservation_CancelReservationByDoctor(
|
||||||
|
$clinicSlug: String!, $reservationId: UUID!
|
||||||
|
) {
|
||||||
|
reservation: cancelReservationByDoctor(
|
||||||
|
clinicSlug: $clinicSlug, reservationId: $reservationId
|
||||||
|
) { id __typename }
|
||||||
|
}"""
|
||||||
|
|
||||||
|
MUTATION_RECURRING = """mutation UpdateReservation_CancelRecurringReservationByDoctor(
|
||||||
|
$input: RemoveRecurringReservationInput!
|
||||||
|
) {
|
||||||
|
success: removeDateFromRecurringReservation(input: $input)
|
||||||
|
}"""
|
||||||
|
|
||||||
|
|
||||||
|
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(value) -> str:
|
||||||
|
"""Prijme str/datetime/date a vrati '....000Z'."""
|
||||||
|
if isinstance(value, str):
|
||||||
|
if value.endswith("Z") and "T" in value:
|
||||||
|
return value
|
||||||
|
dt = dtparser.parse(value)
|
||||||
|
elif isinstance(value, datetime):
|
||||||
|
dt = value
|
||||||
|
else:
|
||||||
|
raise TypeError(f"Nelze prevest na datetime: {value!r}")
|
||||||
|
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 _post(payload: dict, label: str, save_debug: bool = True) -> dict:
|
||||||
|
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)
|
||||||
|
p = DEBUG_DIR / f"smaz_{label}_{datetime.now():%Y%m%d_%H%M%S}.json"
|
||||||
|
p.write_text(
|
||||||
|
json.dumps({"request": payload["variables"], "response": data}, ensure_ascii=False, indent=2),
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
print(f"[debug] {p}")
|
||||||
|
|
||||||
|
if "errors" in data:
|
||||||
|
raise RuntimeError(f"GraphQL error: {data['errors']}")
|
||||||
|
return data["data"]
|
||||||
|
|
||||||
|
|
||||||
|
def smaz_jednorazovou(reservation_id: str, clinic_slug: str = CLINIC_SLUG) -> dict:
|
||||||
|
"""Zrusi (cancel) jednorazovou rezervaci. Vraci {'id': ..., '__typename': ...}."""
|
||||||
|
payload = {
|
||||||
|
"operationName": "UpdateReservation_CancelReservationByDoctor",
|
||||||
|
"variables": {"clinicSlug": clinic_slug, "reservationId": reservation_id},
|
||||||
|
"query": MUTATION_SINGLE,
|
||||||
|
}
|
||||||
|
result = _post(payload, "single")["reservation"]
|
||||||
|
print(f"OK zruseno: {result['id']}")
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def smaz_opakujici(
|
||||||
|
recurring_id: str,
|
||||||
|
date,
|
||||||
|
update_type: str = "ThisAndFuture",
|
||||||
|
clinic_slug: str = CLINIC_SLUG,
|
||||||
|
) -> bool:
|
||||||
|
"""Smaze opakujici se rezervaci.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
recurring_id: UUID `recurringReservation.id`
|
||||||
|
date: datum konkretni instance (ISO str s Z, nebo datetime, nebo 'YYYY-MM-DD HH:MM' v lokal cas)
|
||||||
|
update_type: 'Single' | 'ThisAndFuture' (default) | 'All'
|
||||||
|
"""
|
||||||
|
if update_type not in VALID_UPDATE_TYPES:
|
||||||
|
raise ValueError(f"update_type musi byt {VALID_UPDATE_TYPES}, dostal '{update_type}'")
|
||||||
|
payload = {
|
||||||
|
"operationName": "UpdateReservation_CancelRecurringReservationByDoctor",
|
||||||
|
"variables": {
|
||||||
|
"input": {
|
||||||
|
"clinicSlug": clinic_slug,
|
||||||
|
"recurringReservationId": recurring_id,
|
||||||
|
"date": _to_utc_iso(date),
|
||||||
|
"updateType": update_type,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": MUTATION_RECURRING,
|
||||||
|
}
|
||||||
|
success = _post(payload, f"recurring_{update_type}")["success"]
|
||||||
|
print(f"OK smazano ({update_type}): {recurring_id} @ {payload['variables']['input']['date']} -> success={success}")
|
||||||
|
return success
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
ap = argparse.ArgumentParser(description="Smazani rezervace v Medevio kalendari.")
|
||||||
|
g = ap.add_mutually_exclusive_group(required=True)
|
||||||
|
g.add_argument("--jednorazova", help="UUID jednorazove rezervace ke zruseni")
|
||||||
|
g.add_argument("--opakujici", help="UUID opakujiciho se pravidla")
|
||||||
|
ap.add_argument("--datum", help="Datum instance opakujici (ISO Z nebo 'YYYY-MM-DD HH:MM')")
|
||||||
|
ap.add_argument("--typ", choices=VALID_UPDATE_TYPES, default="ThisAndFuture",
|
||||||
|
help="Pro --opakujici. Default ThisAndFuture.")
|
||||||
|
args = ap.parse_args()
|
||||||
|
|
||||||
|
if args.jednorazova:
|
||||||
|
smaz_jednorazovou(args.jednorazova)
|
||||||
|
else:
|
||||||
|
if not args.datum:
|
||||||
|
ap.error("--opakujici vyzaduje --datum")
|
||||||
|
smaz_opakujici(args.opakujici, args.datum, update_type=args.typ)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
#!/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()
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
"""
|
||||||
|
fill_poukaz_dp.py
|
||||||
|
-----------------
|
||||||
|
Vyplní formulář "Poukaz na vyšetření / ošetření DP" (VZP-06dp/2024).
|
||||||
|
Vstup: PDF šablona (plochý formulář)
|
||||||
|
Výstup: vyplněný PDF
|
||||||
|
|
||||||
|
Použití:
|
||||||
|
python fill_poukaz_dp.py
|
||||||
|
|
||||||
|
Závislosti:
|
||||||
|
pip install pypdf reportlab
|
||||||
|
"""
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
from reportlab.pdfgen import canvas
|
||||||
|
from reportlab.lib.pagesizes import A4
|
||||||
|
from reportlab.pdfbase import pdfmetrics
|
||||||
|
from reportlab.pdfbase.ttfonts import TTFont
|
||||||
|
from pypdf import PdfReader, PdfWriter
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# NASTAVENÍ — sem doplňte cestu k šabloně a výstupnímu souboru
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
SABLONA = Path(__file__).parent / "Poukaz DP zdroj.pdf"
|
||||||
|
VYSTUP = Path(__file__).parent / "Poukaz DP vyplneny.pdf"
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# DATA FORMULÁŘE — doplňte hodnoty
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
DATA = {
|
||||||
|
# ── Hlavička ─────────────────────────────────────────────────────────────
|
||||||
|
"kod_pojistovny": "111", # 3 číslice (VZP = 111)
|
||||||
|
"icp": "12345678", # IČP pracoviště
|
||||||
|
"odbornost": "001", # odbornost
|
||||||
|
"datum": "22.05.2026", # datum vystavení
|
||||||
|
"poradove_cislo": "42", # pořadové č. poukazu / nepřerušené DP
|
||||||
|
"platnost_do": "22.08.2026", # platnost poukazu
|
||||||
|
|
||||||
|
# ── Pacient ──────────────────────────────────────────────────────────────
|
||||||
|
"pacient": "Novák Jan",
|
||||||
|
"cislo_pojistence": "7001015432",
|
||||||
|
"zkladni_dg": "I10", # základní diagnóza (MKN kód)
|
||||||
|
"variabilni_symbol":"123456",
|
||||||
|
"ost_dg": "E11", # ostatní diagnózy
|
||||||
|
"kod_nahrady": "",
|
||||||
|
|
||||||
|
# ── Adresa a kontakty ────────────────────────────────────────────────────
|
||||||
|
"adresa_pacienta": "Dlouhá 12, 110 00 Praha 1, tel: 777 123 456",
|
||||||
|
"dalsi_prislusnici":"ne", # "ano" nebo "ne"
|
||||||
|
"kontaktni_osoba": "Nováková Marie (manželka), tel: 777 654 321",
|
||||||
|
|
||||||
|
# ── Klinické údaje ────────────────────────────────────────────────────────
|
||||||
|
"pecovatelska_sluzba": "ne", # "ano" nebo "ne"
|
||||||
|
"mobilita": "b) omezená: chodí s holí",
|
||||||
|
"smyslove_omezeni": "zraková vada – brýle",
|
||||||
|
"sebeobsluha": "b) omezená: potřebuje pomoc při hygieně",
|
||||||
|
"medikace": "Metformin 1000 mg 1-0-1, Amlodipine 5 mg 1-0-0, inzulín Lantus 20j večer",
|
||||||
|
"dalsi_informace": "alergie: penicilin; inkontinence moči; byt 2. patro bez výtahu",
|
||||||
|
"cil_dp": "Edukace v aplikaci inzulínu, kontrola glykémie, péče o DM nohu",
|
||||||
|
|
||||||
|
# ── Požadované výkony (max 5 řádků) ─────────────────────────────────────
|
||||||
|
# Každý výkon: {"kod": "06101", "popis": "...", "popis2": "..."}
|
||||||
|
"pozadovano": [
|
||||||
|
{"kod": "06101", "popis": "Komplexní ošetřovatelská péče – 1× denně, 5× týdně", "popis2": ""},
|
||||||
|
{"kod": "06129", "popis": "Aplikace inzulínu – 1× denně, 7× týdně", "popis2": ""},
|
||||||
|
{"kod": "06111", "popis": "Odběr biologického materiálu – 1× týdně", "popis2": ""},
|
||||||
|
{"kod": "", "popis": "", "popis2": ""},
|
||||||
|
{"kod": "", "popis": "", "popis2": ""},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Pomocná funkce — zkrátí text pokud je moc dlouhý
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
def _fit(text: str, max_chars: int) -> str:
|
||||||
|
return text[:max_chars] + "…" if len(text) > max_chars else text
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Vytvoří overlay stránku s textem
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
def _vytvor_overlay(data: dict) -> BytesIO:
|
||||||
|
buf = BytesIO()
|
||||||
|
W, H = A4 # 595.3 × 841.9 pt
|
||||||
|
|
||||||
|
c = canvas.Canvas(buf, pagesize=A4)
|
||||||
|
c.setFont("Helvetica", 8)
|
||||||
|
|
||||||
|
def txt(x, y, text, size=8, bold=False):
|
||||||
|
if not text:
|
||||||
|
return
|
||||||
|
font = "Helvetica-Bold" if bold else "Helvetica"
|
||||||
|
c.setFont(font, size)
|
||||||
|
c.drawString(x, y, str(text))
|
||||||
|
|
||||||
|
# ── Hlavička ─────────────────────────────────────────────────────────────
|
||||||
|
txt(58, 795, data["kod_pojistovny"], size=8) # Kód pojišťovny
|
||||||
|
txt(200, 800, data["icp"], size=8) # IČP
|
||||||
|
txt(200, 782, data["odbornost"], size=8) # Odbornost
|
||||||
|
txt(310, 800, data["datum"], size=8) # Datum
|
||||||
|
txt(425, 800, data["poradove_cislo"], size=8) # Pořadové č.
|
||||||
|
txt(470, 765, data["platnost_do"], size=8) # Platnost do
|
||||||
|
|
||||||
|
# ── Pacient ──────────────────────────────────────────────────────────────
|
||||||
|
txt(195, 726, _fit(data["pacient"], 40), size=8) # Pacient
|
||||||
|
txt(115, 709, data["cislo_pojistence"], size=8) # Č. pojištěnce
|
||||||
|
txt(390, 709, data["zkladni_dg"], size=8) # Základní dg.
|
||||||
|
txt(115, 692, data["variabilni_symbol"], size=8) # Variabilní symbol
|
||||||
|
txt(390, 692, data["ost_dg"], size=8) # Ost. dg.
|
||||||
|
txt(390, 675, data["kod_nahrady"], size=8) # Kód náhrady
|
||||||
|
|
||||||
|
# ── Adresa pacienta ───────────────────────────────────────────────────────
|
||||||
|
txt(335, 634, _fit(data["adresa_pacienta"], 70), size=8)
|
||||||
|
|
||||||
|
# Další příslušníci — podtrhne zvolenou možnost
|
||||||
|
if data["dalsi_prislusnici"].lower() == "ano":
|
||||||
|
txt(310, 600, "ano", size=8, bold=True)
|
||||||
|
else:
|
||||||
|
txt(323, 600, "ne", size=8, bold=True)
|
||||||
|
|
||||||
|
# ── Kontaktní osoba ───────────────────────────────────────────────────────
|
||||||
|
txt(420, 573, _fit(data["kontaktni_osoba"], 50), size=8)
|
||||||
|
|
||||||
|
# Pacient v péči pečovatelské služby
|
||||||
|
if data["pecovatelska_sluzba"].lower() == "ano":
|
||||||
|
txt(310, 536, "ano", size=8, bold=True)
|
||||||
|
else:
|
||||||
|
txt(323, 536, "ne", size=8, bold=True)
|
||||||
|
|
||||||
|
# ── Mobilita ──────────────────────────────────────────────────────────────
|
||||||
|
mob = data["mobilita"]
|
||||||
|
if mob.lower().startswith("a"):
|
||||||
|
txt(230, 521, "✓ plná", size=8, bold=True)
|
||||||
|
else:
|
||||||
|
# odstraní "b) omezená:" prefix pokud tam je
|
||||||
|
detail = mob.replace("b) omezená:", "").replace("b)omezená:", "").strip()
|
||||||
|
txt(280, 504, _fit(detail, 60), size=8)
|
||||||
|
|
||||||
|
# ── Smyslové omezení ──────────────────────────────────────────────────────
|
||||||
|
txt(280, 479, _fit(data["smyslove_omezeni"], 65), size=8)
|
||||||
|
|
||||||
|
# ── Sebeobsluha ───────────────────────────────────────────────────────────
|
||||||
|
sebo = data["sebeobsluha"]
|
||||||
|
if sebo.lower().startswith("a"):
|
||||||
|
txt(390, 452, "✓ plná", size=8, bold=True)
|
||||||
|
else:
|
||||||
|
detail = sebo.replace("b) omezená:", "").replace("b)omezená:", "").strip()
|
||||||
|
txt(280, 437, _fit(detail, 60), size=8)
|
||||||
|
|
||||||
|
# ── Medikace (max 3 řádky) ────────────────────────────────────────────────
|
||||||
|
med_lines = _rozlom(data["medikace"], 80)
|
||||||
|
for i, line in enumerate(med_lines[:3]):
|
||||||
|
txt(58, 413 - i * 14, line, size=8)
|
||||||
|
|
||||||
|
# ── Další informace (max 3 řádky) ─────────────────────────────────────────
|
||||||
|
info_lines = _rozlom(data["dalsi_informace"], 80)
|
||||||
|
for i, line in enumerate(info_lines[:3]):
|
||||||
|
txt(58, 370 - i * 14, line, size=8)
|
||||||
|
|
||||||
|
# ── Cíl DP (max 2 řádky) ──────────────────────────────────────────────────
|
||||||
|
cil_lines = _rozlom(data["cil_dp"], 80)
|
||||||
|
for i, line in enumerate(cil_lines[:2]):
|
||||||
|
txt(58, 321 - i * 14, line, size=8)
|
||||||
|
|
||||||
|
# ── Požadované výkony ─────────────────────────────────────────────────────
|
||||||
|
# Souřadnice každého řádku (y pro kód, y pro 1. text, y pro 2. text)
|
||||||
|
radky = [
|
||||||
|
(240, 263, 243), # řádek 1
|
||||||
|
(197, 210, 192), # řádek 2
|
||||||
|
(152, 163, 145), # řádek 3
|
||||||
|
(110, 120, 102), # řádek 4
|
||||||
|
( 68, 78, 60), # řádek 5
|
||||||
|
]
|
||||||
|
|
||||||
|
for i, vykon in enumerate(data["pozadovano"][:5]):
|
||||||
|
y_kod, y_txt1, y_txt2 = radky[i]
|
||||||
|
txt(58, y_kod, vykon.get("kod", ""), size=8)
|
||||||
|
txt(285, y_txt1, _fit(vykon.get("popis", ""), 75), size=8)
|
||||||
|
txt(285, y_txt2, _fit(vykon.get("popis2", ""), 75), size=8)
|
||||||
|
|
||||||
|
c.save()
|
||||||
|
buf.seek(0)
|
||||||
|
return buf
|
||||||
|
|
||||||
|
|
||||||
|
def _rozlom(text: str, sirka: int) -> list[str]:
|
||||||
|
"""Rozlomí dlouhý text na řádky po max `sirka` znacích (na hranici slova)."""
|
||||||
|
words = text.split()
|
||||||
|
lines, current = [], ""
|
||||||
|
for w in words:
|
||||||
|
if len(current) + len(w) + 1 <= sirka:
|
||||||
|
current = (current + " " + w).strip()
|
||||||
|
else:
|
||||||
|
if current:
|
||||||
|
lines.append(current)
|
||||||
|
current = w
|
||||||
|
if current:
|
||||||
|
lines.append(current)
|
||||||
|
return lines
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Hlavní funkce
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
def vyplnit_poukaz(data: dict, sablona: Path, vystup: Path):
|
||||||
|
if not sablona.exists():
|
||||||
|
raise FileNotFoundError(f"Šablona nenalezena: {sablona}")
|
||||||
|
|
||||||
|
overlay_buf = _vytvor_overlay(data)
|
||||||
|
|
||||||
|
reader = PdfReader(sablona)
|
||||||
|
writer = PdfWriter()
|
||||||
|
overlay = PdfReader(overlay_buf)
|
||||||
|
|
||||||
|
# Stránka 1 — překryjeme overlayem
|
||||||
|
page1 = reader.pages[0]
|
||||||
|
page1.merge_page(overlay.pages[0])
|
||||||
|
writer.add_page(page1)
|
||||||
|
|
||||||
|
# Stránka 2 — beze změny
|
||||||
|
if len(reader.pages) > 1:
|
||||||
|
writer.add_page(reader.pages[1])
|
||||||
|
|
||||||
|
vystup.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
with open(vystup, "wb") as f:
|
||||||
|
writer.write(f)
|
||||||
|
|
||||||
|
print(f"✓ Hotovo: {vystup}")
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
if __name__ == "__main__":
|
||||||
|
vyplnit_poukaz(DATA, SABLONA, VYSTUP)
|
||||||
@@ -0,0 +1,595 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
poukaz_dp_gen.py
|
||||||
|
Generátor Poukazu na vyšetření/ošetření DP (VZP-06dp/2024).
|
||||||
|
Formulář je kreslen od nuly pomocí reportlab – žádné překrývání PDF šablony.
|
||||||
|
|
||||||
|
Závislosti:
|
||||||
|
pip install reportlab
|
||||||
|
"""
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from reportlab.pdfgen import canvas
|
||||||
|
from reportlab.lib.pagesizes import A4
|
||||||
|
from reportlab.pdfbase import pdfmetrics
|
||||||
|
from reportlab.pdfbase.ttfonts import TTFont
|
||||||
|
|
||||||
|
# ── Registrace fontu s českou podporou ────────────────────────────────────────
|
||||||
|
def _reg_font():
|
||||||
|
candidates = [
|
||||||
|
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
|
||||||
|
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
|
||||||
|
"C:/Windows/Fonts/arial.ttf",
|
||||||
|
"C:/Windows/Fonts/arialbd.ttf",
|
||||||
|
]
|
||||||
|
reg, reg_bold = False, False
|
||||||
|
for p in candidates:
|
||||||
|
if Path(p).exists():
|
||||||
|
if not reg and "Bold" not in p and "bd" not in p:
|
||||||
|
pdfmetrics.registerFont(TTFont("Czech", p))
|
||||||
|
reg = True
|
||||||
|
elif not reg_bold and ("Bold" in p or "bd" in p):
|
||||||
|
pdfmetrics.registerFont(TTFont("Czech-Bold", p))
|
||||||
|
reg_bold = True
|
||||||
|
if not reg:
|
||||||
|
# fallback – Helvetica (funguje pro základní znaky)
|
||||||
|
return "Helvetica", "Helvetica-Bold"
|
||||||
|
if not reg_bold:
|
||||||
|
return "Czech", "Czech"
|
||||||
|
return "Czech", "Czech-Bold"
|
||||||
|
|
||||||
|
FONT, FONT_BOLD = _reg_font()
|
||||||
|
|
||||||
|
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
# DATA FORMULÁŘE – sem doplňte hodnoty z Medicusu
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
DATA = {
|
||||||
|
# ── Hlavička ──────────────────────────────────────────────────────────────
|
||||||
|
"kod_pojistovny": "111", # 3 číslice, VZP = 111
|
||||||
|
"icp": "12345678", # IČP pracoviště (max 8 číslic)
|
||||||
|
"odbornost": "001", # odbornost (3 číslice)
|
||||||
|
"datum": "22.05.2026", # datum vystavení
|
||||||
|
"poradove_cislo": "42", # pořadové číslo / nepřerušené DP
|
||||||
|
"platnost_do": "22.08.2026", # platnost poukazu
|
||||||
|
|
||||||
|
# ── Pacient ───────────────────────────────────────────────────────────────
|
||||||
|
"pacient": "Novák Jan",
|
||||||
|
"cislo_pojistence": "7001015432", # rodné číslo / č. pojištěnce
|
||||||
|
"zkladni_dg": "I10", # MKN kód základní diagnózy
|
||||||
|
"variabilni_symbol": "123456",
|
||||||
|
"ost_dg": "E11", # ostatní diagnózy
|
||||||
|
"kod_nahrady": "",
|
||||||
|
|
||||||
|
# ── Adresa a kontakty ─────────────────────────────────────────────────────
|
||||||
|
"adresa_pacienta": "Dlouhá 12, 110 00 Praha 1, tel: 777 123 456",
|
||||||
|
|
||||||
|
"dalsi_prislusnici": "ne", # "ano" / "ne"
|
||||||
|
"kontaktni_osoba": "Nováková Marie (manželka), tel: 777 654 321",
|
||||||
|
|
||||||
|
# ── Klinické údaje ────────────────────────────────────────────────────────
|
||||||
|
"pecovatelska_sluzba": "ne", # "ano" / "ne"
|
||||||
|
|
||||||
|
"mobilita": "b", # "a" = plná / "b" = omezená
|
||||||
|
"mobilita_detail": "chodí s holí",
|
||||||
|
|
||||||
|
"smyslove_omezeni": "zraková vada – brýle",
|
||||||
|
|
||||||
|
"sebeobsluha": "b", # "a" = plná / "b" = omezená
|
||||||
|
"sebeobsluha_detail": "potřebuje pomoc při hygieně",
|
||||||
|
|
||||||
|
# Každá položka = jeden řádek (max 3)
|
||||||
|
"medikace": [
|
||||||
|
"Metformin 1000 mg 1-0-1, Amlodipine 5 mg 1-0-0",
|
||||||
|
"Inzulín Lantus 20j večer",
|
||||||
|
],
|
||||||
|
|
||||||
|
"dalsi_informace": [
|
||||||
|
"alergie: penicilin; inkontinence moči",
|
||||||
|
"byt 2. patro bez výtahu",
|
||||||
|
],
|
||||||
|
|
||||||
|
"cil_dp": [
|
||||||
|
"Edukace v aplikaci inzulínu, kontrola glykémie, péče o DM nohu",
|
||||||
|
],
|
||||||
|
|
||||||
|
# ── Požadované výkony (max 5) ─────────────────────────────────────────────
|
||||||
|
# kod … kód výkonu (max 5 číslic)
|
||||||
|
# popis … text na prvním řádku
|
||||||
|
# popis2 … pokračování na druhém řádku (nepovinné)
|
||||||
|
"pozadovano": [
|
||||||
|
{"kod": "06101", "popis": "Komplexní ošetřovatelská péče – 1× denně, 5× týdně", "popis2": ""},
|
||||||
|
{"kod": "06129", "popis": "Aplikace inzulínu – 1× denně, 7× týdně", "popis2": ""},
|
||||||
|
{"kod": "06111", "popis": "Odběr biologického materiálu – 1× týdně", "popis2": ""},
|
||||||
|
{"kod": "", "popis": "", "popis2": ""},
|
||||||
|
{"kod": "", "popis": "", "popis2": ""},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
# GEOMETRIE (souřadnice od SHORA, konverze na RL přes yt())
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
PAGE_W, PAGE_H = A4 # 595 × 842 pt
|
||||||
|
|
||||||
|
# Vnější zaoblený rámeček
|
||||||
|
FX1, FX2 = 28, 567 # levý / pravý okraj
|
||||||
|
FB, FT = 52, 818 # spodní / horní okraj (RL souřadnice od zdola)
|
||||||
|
|
||||||
|
IL = FX1 + 7 # inner left (odsazení textu od okraje)
|
||||||
|
IR = FX2 - 7 # inner right
|
||||||
|
|
||||||
|
|
||||||
|
def yt(from_top: float) -> float:
|
||||||
|
"""Převede y-od-shora (pt) na reportlab y-od-zdola."""
|
||||||
|
return PAGE_H - from_top
|
||||||
|
|
||||||
|
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
# POMOCNÉ FUNKCE
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
def txt(c, x, y_rl, text, size=7.5, bold=False, align="left"):
|
||||||
|
if not text:
|
||||||
|
return
|
||||||
|
c.setFont(FONT_BOLD if bold else FONT, size)
|
||||||
|
if align == "right":
|
||||||
|
c.drawRightString(x, y_rl, str(text))
|
||||||
|
elif align == "center":
|
||||||
|
c.drawCentredString(x, y_rl, str(text))
|
||||||
|
else:
|
||||||
|
c.drawString(x, y_rl, str(text))
|
||||||
|
|
||||||
|
|
||||||
|
def hline(c, x1, y_rl, x2=None, w=0.5):
|
||||||
|
if x2 is None:
|
||||||
|
x2 = IR
|
||||||
|
c.setLineWidth(w)
|
||||||
|
c.setDash([])
|
||||||
|
c.line(x1, y_rl, x2, y_rl)
|
||||||
|
|
||||||
|
|
||||||
|
def vline(c, x, y1_rl, y2_rl, w=0.5):
|
||||||
|
c.setLineWidth(w)
|
||||||
|
c.setDash([])
|
||||||
|
c.line(x, y1_rl, x, y2_rl)
|
||||||
|
|
||||||
|
|
||||||
|
def dotline(c, x1, y_rl, x2=None):
|
||||||
|
if x2 is None:
|
||||||
|
x2 = IR
|
||||||
|
c.setLineWidth(0.35)
|
||||||
|
c.setDash([1.5, 2.5])
|
||||||
|
c.line(x1, y_rl, x2, y_rl)
|
||||||
|
c.setDash([])
|
||||||
|
|
||||||
|
|
||||||
|
def chkbox(c, x, y_rl, checked: bool, size=7):
|
||||||
|
"""Zaškrtávací políčko."""
|
||||||
|
c.setLineWidth(0.6)
|
||||||
|
c.setDash([])
|
||||||
|
c.rect(x, y_rl - 1, size, size, stroke=1, fill=0)
|
||||||
|
if checked:
|
||||||
|
c.setFont(FONT_BOLD, size - 0.5)
|
||||||
|
c.drawString(x + 1, y_rl, "✓")
|
||||||
|
|
||||||
|
|
||||||
|
def digit_box(c, x, y_rl, width, height, digits, value_text=""):
|
||||||
|
"""Prostý rámeček pro zadávání hodnot (bez vnitřních oddělovačů)."""
|
||||||
|
c.setLineWidth(0.7)
|
||||||
|
c.setDash([])
|
||||||
|
c.rect(x, y_rl, width, height, stroke=1, fill=0)
|
||||||
|
if value_text:
|
||||||
|
c.setFont(FONT, height * 0.65)
|
||||||
|
c.drawString(x + 3, y_rl + height * 0.2, value_text[:digits])
|
||||||
|
|
||||||
|
|
||||||
|
def wrap(text: str, max_chars: int) -> list[str]:
|
||||||
|
"""Rozlomí text na řádky po max_chars znacích (na hranici slova)."""
|
||||||
|
if not text:
|
||||||
|
return [""]
|
||||||
|
words = text.split()
|
||||||
|
lines, cur = [], ""
|
||||||
|
for w in words:
|
||||||
|
if cur and len(cur) + 1 + len(w) > max_chars:
|
||||||
|
lines.append(cur)
|
||||||
|
cur = w
|
||||||
|
else:
|
||||||
|
cur = (cur + " " + w).strip()
|
||||||
|
if cur:
|
||||||
|
lines.append(cur)
|
||||||
|
return lines or [""]
|
||||||
|
|
||||||
|
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
# SEKCE 1: HLAVIČKA
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
#
|
||||||
|
# ┌─────────────────┬──────────┬──────────────────────┬──────────────────────┐
|
||||||
|
# │ Kód pojišťovny │ požaduje │ IČP [________] Datum [________] │ Pořadové číslo…
|
||||||
|
# │ [___] │ díl A │ Odbornost [___] │ nepřerušené DP:
|
||||||
|
# └─────────────────┴──────────┴──────────────────────┴──────────────────────┘
|
||||||
|
# Platnost do:
|
||||||
|
|
||||||
|
HDR_TOP = 25 # horní okraj formuláře (od shora)
|
||||||
|
HDR_MID = 50 # vodorovná čára mezi řádky hlavičky
|
||||||
|
HDR_BOT = 73 # dolní okraj hlavičky
|
||||||
|
|
||||||
|
# Svislé dělicí čáry v hlavičce
|
||||||
|
HX1 = 130 # po Kód pojišťovny
|
||||||
|
HX2 = 198 # po požaduje díl A
|
||||||
|
HX3 = 295 # mezi IČP a Datum
|
||||||
|
HX4 = 388 # konec IČP+Datum sekce (začátek Pořadové číslo)
|
||||||
|
|
||||||
|
|
||||||
|
def draw_hlavicka(c, d):
|
||||||
|
# Vnější rámeček hlavičky
|
||||||
|
hline(c, FX1, yt(HDR_BOT), FX2, w=1.2)
|
||||||
|
hline(c, FX1, yt(HDR_MID), HX4, w=0.5)
|
||||||
|
|
||||||
|
# Svislé čáry
|
||||||
|
for x in (HX1, HX2, HX4):
|
||||||
|
vline(c, x, yt(HDR_TOP), yt(HDR_BOT), w=0.8)
|
||||||
|
vline(c, HX3, yt(HDR_TOP), yt(HDR_MID), w=0.5)
|
||||||
|
|
||||||
|
# Kód pojišťovny
|
||||||
|
txt(c, IL, yt(HDR_TOP + 7), "Kód pojišťovny", size=6.5)
|
||||||
|
digit_box(c, IL, yt(HDR_MID - 5), 40, 12, 3, d.get("kod_pojistovny", ""))
|
||||||
|
|
||||||
|
# požaduje díl A
|
||||||
|
cx = (HX1 + HX2) / 2
|
||||||
|
txt(c, cx, yt(HDR_TOP + 12), "požaduje", size=7, bold=True, align="center")
|
||||||
|
txt(c, cx, yt(HDR_TOP + 21), "díl A", size=7, bold=True, align="center")
|
||||||
|
|
||||||
|
# IČP
|
||||||
|
txt(c, HX2 + 3, yt(HDR_TOP + 7), "IČP", size=6.5)
|
||||||
|
digit_box(c, HX2 + 22, yt(HDR_MID - 5), HX3 - HX2 - 27, 12, 8, d.get("icp", ""))
|
||||||
|
|
||||||
|
# Datum
|
||||||
|
txt(c, HX3 + 3, yt(HDR_TOP + 7), "Datum", size=6.5)
|
||||||
|
digit_box(c, HX3 + 28, yt(HDR_MID - 5), HX4 - HX3 - 32, 12, 10, d.get("datum", ""))
|
||||||
|
|
||||||
|
# Odbornost
|
||||||
|
txt(c, HX2 + 3, yt(HDR_MID + 7), "Odbornost", size=6.5)
|
||||||
|
digit_box(c, HX2 + 48, yt(HDR_BOT - 5), HX3 - HX2 - 52, 12, 3, d.get("odbornost", ""))
|
||||||
|
|
||||||
|
# Pořadové číslo (pravý sloupec)
|
||||||
|
txt(c, HX4 + 4, yt(HDR_TOP + 21), "Pořadové číslo poukazu", size=6.5)
|
||||||
|
txt(c, HX4 + 4, yt(HDR_TOP + 30), "nepřerušené DP:", size=6.5)
|
||||||
|
txt(c, HX4 + 80, yt(HDR_TOP + 36), d.get("poradove_cislo", ""), size=8)
|
||||||
|
|
||||||
|
# Platnost do
|
||||||
|
txt(c, HX4 + 4, yt(HDR_MID + 19), "Platnost do:", size=6.5)
|
||||||
|
hline(c, HX4 + 50, yt(HDR_MID + 13), FX2 - 4, w=0.4)
|
||||||
|
txt(c, HX4 + 54, yt(HDR_MID + 25), d.get("platnost_do", ""), size=8)
|
||||||
|
|
||||||
|
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
# SEKCE 2: NADPIS
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
TTL_TOP = HDR_BOT # 73
|
||||||
|
TTL_BOT = TTL_TOP + 22 # 95
|
||||||
|
|
||||||
|
|
||||||
|
def draw_nadpis(c):
|
||||||
|
hline(c, FX1, yt(TTL_BOT), FX2, w=0.8)
|
||||||
|
# "POUKAZ NA VYŠETŘENÍ / OŠETŘENÍ"
|
||||||
|
c.setFont(FONT_BOLD, 12)
|
||||||
|
c.drawCentredString(270, yt(TTL_TOP + 15), "POUKAZ NA VYŠETŘENÍ / OŠETŘENÍ")
|
||||||
|
# "DP" – velké
|
||||||
|
c.setFont(FONT_BOLD, 22)
|
||||||
|
c.drawString(390, yt(TTL_TOP + 18), "DP")
|
||||||
|
|
||||||
|
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
# SEKCE 3: BLOK PACIENTA
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
PAC_TOP = TTL_BOT # 95
|
||||||
|
PAC_ROW = 19 # výška každého řádku
|
||||||
|
PAC_BOT = PAC_TOP + 4 * PAC_ROW # 171
|
||||||
|
|
||||||
|
# Svislé dělicí čáry v bloku pacienta
|
||||||
|
PX1 = 340 # Č. pojištěnce / Základní diagnóza
|
||||||
|
PX2 = 340 # (sdílí s PX1 pro 2. a 3. řádek)
|
||||||
|
PX3 = 410 # Ost. dg. / Kód náhrady
|
||||||
|
|
||||||
|
# Šířka bloku pacienta (bez pravého sloupce s razítkem)
|
||||||
|
PAC_RIGHT = 540 # pravý okraj tabulky pacienta
|
||||||
|
|
||||||
|
|
||||||
|
def draw_pacient(c, d):
|
||||||
|
# Vnější pravý okraj tabulky pacienta
|
||||||
|
vline(c, PAC_RIGHT, yt(PAC_TOP), yt(PAC_BOT), w=1.0)
|
||||||
|
|
||||||
|
# Řádek 1: Pacient
|
||||||
|
y1 = yt(PAC_TOP + PAC_ROW)
|
||||||
|
hline(c, FX1, y1, PAC_RIGHT, w=0.6)
|
||||||
|
txt(c, IL, y1 + 5, "Pacient", size=7)
|
||||||
|
txt(c, IL + 50, y1 + 5, d.get("pacient", ""), size=8.5)
|
||||||
|
|
||||||
|
# Řádek 2: Č. pojištěnce | Základní diagnóza
|
||||||
|
y2 = yt(PAC_TOP + 2 * PAC_ROW)
|
||||||
|
hline(c, FX1, y2, PAC_RIGHT, w=0.6)
|
||||||
|
vline(c, PX1, yt(PAC_TOP + PAC_ROW), y2, w=0.5)
|
||||||
|
txt(c, IL, y2 + 5, "Č. pojištěnce", size=7)
|
||||||
|
digit_box(c, IL + 68, y2 + 3, 130, 13, 10, d.get("cislo_pojistence", ""))
|
||||||
|
txt(c, PX1 + 4, y2 + 5, "Základní diagnóza", size=7)
|
||||||
|
digit_box(c, PX1 + 86, y2 + 3, 65, 13, 5, d.get("zkladni_dg", ""))
|
||||||
|
|
||||||
|
# Řádek 3: Variabilní symbol | Ost. dg. | Kód náhrady
|
||||||
|
y3 = yt(PAC_TOP + 3 * PAC_ROW)
|
||||||
|
hline(c, FX1, y3, PAC_RIGHT, w=0.6)
|
||||||
|
vline(c, PX2, yt(PAC_TOP + 2 * PAC_ROW), y3, w=0.5)
|
||||||
|
vline(c, PX3, yt(PAC_TOP + 2 * PAC_ROW), y3, w=0.5)
|
||||||
|
txt(c, IL, y3 + 5, "Variabilní symbol", size=7)
|
||||||
|
digit_box(c, IL + 83, y3 + 3, 100, 13, 8, d.get("variabilni_symbol", ""))
|
||||||
|
txt(c, PX2 + 4, y3 + 5, "Ost. dg.", size=7)
|
||||||
|
digit_box(c, PX2 + 38, y3 + 3, 60, 13, 5, d.get("ost_dg", ""))
|
||||||
|
txt(c, PX3 + 4, y3 + 5, "Kód náhrady", size=7)
|
||||||
|
digit_box(c, PX3 + 54, y3 + 3, 50, 13, 4, d.get("kod_nahrady", ""))
|
||||||
|
|
||||||
|
# Řádek 4: Ad zařízení domácí péče + razítko
|
||||||
|
y4 = yt(PAC_BOT)
|
||||||
|
hline(c, FX1, y4, PAC_RIGHT, w=0.6)
|
||||||
|
txt(c, IL, y4 + 5, "Ad zařízení domácí péče:", size=7, bold=True)
|
||||||
|
# razítko a podpis (pravý sloupec, malé kurzívní)
|
||||||
|
c.setFont(FONT, 6)
|
||||||
|
c.drawRightString(FX2 - 4, y4 + 4, "razítko a podpis požadujícího")
|
||||||
|
hline(c, PAC_RIGHT + 5, y4 + 2, FX2 - 4, w=0.4)
|
||||||
|
|
||||||
|
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
# SEKCE 4: TEXTOVÁ POLE
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
def draw_textova_pole(c, d) -> float:
|
||||||
|
"""Vrací cur_top (od shora) po posledním poli."""
|
||||||
|
top = PAC_BOT + 6 # 177 od shora
|
||||||
|
LBL = 7.5 # velikost fontu popisků
|
||||||
|
VAL = 8.0 # velikost fontu hodnot
|
||||||
|
GAP = 6 # mezera mezi sekcemi
|
||||||
|
|
||||||
|
def label_and_value(label_text, value_text, label_width, max_chars=70):
|
||||||
|
nonlocal top
|
||||||
|
top += GAP
|
||||||
|
y_rl = yt(top + 9)
|
||||||
|
txt(c, IL, y_rl, label_text, size=LBL)
|
||||||
|
txt(c, IL + label_width, y_rl, value_text[:max_chars] if value_text else "", size=VAL)
|
||||||
|
dotline(c, IL + label_width, y_rl - 2)
|
||||||
|
top += 16
|
||||||
|
|
||||||
|
def extra_dotline(value_text="", indent=0):
|
||||||
|
nonlocal top
|
||||||
|
top += 13
|
||||||
|
y_rl = yt(top)
|
||||||
|
dotline(c, IL + indent, y_rl)
|
||||||
|
if value_text:
|
||||||
|
txt(c, IL + indent, y_rl + 3, value_text[:80], size=VAL)
|
||||||
|
|
||||||
|
def checkbox_row(label_text, field_name, label_width=None):
|
||||||
|
nonlocal top
|
||||||
|
top += GAP
|
||||||
|
y_rl = yt(top + 9)
|
||||||
|
txt(c, IL, y_rl, label_text, size=LBL)
|
||||||
|
lw = label_width or (len(label_text) * 4.2)
|
||||||
|
cx = IL + lw + 5
|
||||||
|
val = d.get(field_name, "ne").lower()
|
||||||
|
chkbox(c, cx, y_rl, checked=(val == "ano"), size=7)
|
||||||
|
txt(c, cx + 9, y_rl, "ano", size=LBL)
|
||||||
|
chkbox(c, cx + 34, y_rl, checked=(val == "ne"), size=7)
|
||||||
|
txt(c, cx + 43, y_rl, "ne", size=LBL)
|
||||||
|
top += 16
|
||||||
|
|
||||||
|
# ── Adresa pacienta ───────────────────────────────────────────────────────
|
||||||
|
adresa_lines = wrap(d.get("adresa_pacienta", ""), 75)
|
||||||
|
label_and_value("Adresa pacienta (místo poskytování DP) a telefon:", adresa_lines[0], 260)
|
||||||
|
extra_dotline(adresa_lines[1] if len(adresa_lines) > 1 else "")
|
||||||
|
|
||||||
|
# ── Příslušníci domácnosti ────────────────────────────────────────────────
|
||||||
|
checkbox_row("Další příslušníci domácnosti na této adrese:", "dalsi_prislusnici", label_width=242)
|
||||||
|
|
||||||
|
# ── Kontaktní osoba ───────────────────────────────────────────────────────
|
||||||
|
kont_lines = wrap(d.get("kontaktni_osoba", ""), 55)
|
||||||
|
label_and_value(
|
||||||
|
"Kontaktní osoba pro DP (jméno, vztah k pacientovi, adresa a telefon – je-li rozdílná od adresy pacienta):",
|
||||||
|
kont_lines[0], 432, max_chars=55
|
||||||
|
)
|
||||||
|
extra_dotline(kont_lines[1] if len(kont_lines) > 1 else "")
|
||||||
|
|
||||||
|
# ── Pečovatelská služba ───────────────────────────────────────────────────
|
||||||
|
checkbox_row("Pacient v péči pečovatelské služby:", "pecovatelska_sluzba", label_width=186)
|
||||||
|
|
||||||
|
# ── Mobilita ──────────────────────────────────────────────────────────────
|
||||||
|
top += GAP
|
||||||
|
y_mob = yt(top + 9)
|
||||||
|
txt(c, IL, y_mob, "Mobilita pacienta:", size=LBL)
|
||||||
|
mob = d.get("mobilita", "a").lower()
|
||||||
|
chkbox(c, IL + 98, y_mob, checked=(mob == "a"), size=7)
|
||||||
|
txt(c, IL + 107, y_mob, "a) plná", size=LBL)
|
||||||
|
top += 16
|
||||||
|
|
||||||
|
top += 2
|
||||||
|
y_mob2 = yt(top + 9)
|
||||||
|
chkbox(c, IL + 98, y_mob2, checked=(mob == "b"), size=7)
|
||||||
|
txt(c, IL + 107, y_mob2, "b) omezená:", size=LBL)
|
||||||
|
mob_detail = d.get("mobilita_detail", "") if mob == "b" else ""
|
||||||
|
txt(c, IL + 167, y_mob2, mob_detail[:60], size=VAL)
|
||||||
|
dotline(c, IL + 163, y_mob2 - 2)
|
||||||
|
top += 16
|
||||||
|
|
||||||
|
# ── Smyslové omezení ──────────────────────────────────────────────────────
|
||||||
|
label_and_value("Smyslové omezení:", d.get("smyslove_omezeni", ""), 95)
|
||||||
|
|
||||||
|
# ── Sebeobsluha ───────────────────────────────────────────────────────────
|
||||||
|
top += GAP
|
||||||
|
y_sebe = yt(top + 9)
|
||||||
|
txt(c, IL, y_sebe, "Schopnost základní sebeobsluhy, včetně dodržování léčebného režimu:", size=LBL)
|
||||||
|
sebe = d.get("sebeobsluha", "a").lower()
|
||||||
|
chkbox(c, IL + 374, y_sebe, checked=(sebe == "a"), size=7)
|
||||||
|
txt(c, IL + 383, y_sebe, "a) plná", size=LBL)
|
||||||
|
top += 16
|
||||||
|
|
||||||
|
top += 2
|
||||||
|
y_sebe2 = yt(top + 9)
|
||||||
|
chkbox(c, IL + 98, y_sebe2, checked=(sebe == "b"), size=7)
|
||||||
|
txt(c, IL + 107, y_sebe2, "b) omezená:", size=LBL)
|
||||||
|
sebe_detail = d.get("sebeobsluha_detail", "") if sebe == "b" else ""
|
||||||
|
txt(c, IL + 167, y_sebe2, sebe_detail[:60], size=VAL)
|
||||||
|
dotline(c, IL + 163, y_sebe2 - 2)
|
||||||
|
top += 16
|
||||||
|
|
||||||
|
# ── Medikace ──────────────────────────────────────────────────────────────
|
||||||
|
med = d.get("medikace", [])
|
||||||
|
if isinstance(med, str):
|
||||||
|
med = [med]
|
||||||
|
med_lines = []
|
||||||
|
for item in med:
|
||||||
|
med_lines.extend(wrap(item, 80))
|
||||||
|
|
||||||
|
top += GAP
|
||||||
|
y_med = yt(top + 9)
|
||||||
|
txt(c, IL, y_med, "Významné údaje o současné medikaci, včetně aplikace inzulínu a diety:", size=LBL)
|
||||||
|
txt(c, IL + 357, y_med, med_lines[0][:35] if med_lines else "", size=VAL)
|
||||||
|
dotline(c, IL + 353, y_med - 2)
|
||||||
|
top += 16
|
||||||
|
extra_dotline(med_lines[1] if len(med_lines) > 1 else "")
|
||||||
|
extra_dotline(med_lines[2] if len(med_lines) > 2 else "")
|
||||||
|
top += 3
|
||||||
|
|
||||||
|
# ── Další informace ───────────────────────────────────────────────────────
|
||||||
|
info = d.get("dalsi_informace", [])
|
||||||
|
if isinstance(info, str):
|
||||||
|
info = [info]
|
||||||
|
info_lines = []
|
||||||
|
for item in info:
|
||||||
|
info_lines.extend(wrap(item, 80))
|
||||||
|
|
||||||
|
top += GAP
|
||||||
|
y_info = yt(top + 9)
|
||||||
|
txt(c, IL, y_info, "Další informace (alergie, kontinence, údaje o bydlišti atd.):", size=LBL)
|
||||||
|
txt(c, IL + 315, y_info, info_lines[0][:40] if info_lines else "", size=VAL)
|
||||||
|
dotline(c, IL + 311, y_info - 2)
|
||||||
|
top += 16
|
||||||
|
extra_dotline(info_lines[1] if len(info_lines) > 1 else "")
|
||||||
|
extra_dotline(info_lines[2] if len(info_lines) > 2 else "")
|
||||||
|
top += 3
|
||||||
|
|
||||||
|
# ── Cíl DP ────────────────────────────────────────────────────────────────
|
||||||
|
cil = d.get("cil_dp", [])
|
||||||
|
if isinstance(cil, str):
|
||||||
|
cil = [cil]
|
||||||
|
cil_lines = []
|
||||||
|
for item in cil:
|
||||||
|
cil_lines.extend(wrap(item, 80))
|
||||||
|
|
||||||
|
top += GAP
|
||||||
|
y_cil = yt(top + 9)
|
||||||
|
txt(c, IL, y_cil, "Cíl předepsané DP, kterého má být dosaženo:", size=LBL)
|
||||||
|
txt(c, IL + 236, y_cil, cil_lines[0][:50] if cil_lines else "", size=VAL)
|
||||||
|
dotline(c, IL + 232, y_cil - 2)
|
||||||
|
top += 16
|
||||||
|
extra_dotline(cil_lines[1] if len(cil_lines) > 1 else "")
|
||||||
|
top += 5
|
||||||
|
|
||||||
|
return top
|
||||||
|
|
||||||
|
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
# SEKCE 5: POŽADOVÁNO
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
def draw_pozadovano(c, d, start_top: float):
|
||||||
|
top = start_top + 5
|
||||||
|
|
||||||
|
# Nadpis
|
||||||
|
top += 8
|
||||||
|
y_hdr = yt(top + 9)
|
||||||
|
txt(c, IL, y_hdr, "Požadováno:", size=8, bold=True)
|
||||||
|
txt(c, IL + 68, y_hdr,
|
||||||
|
"(Pro úhradu požadované péče zdravotní pojišťovnou je nezbytná jednoznačná specifikace požadavku,",
|
||||||
|
size=6.5)
|
||||||
|
top += 12
|
||||||
|
txt(c, IL + 68, yt(top + 5),
|
||||||
|
"včetně počtu v jednom dni a frekvence v týdnu)", size=6.5)
|
||||||
|
top += 10
|
||||||
|
|
||||||
|
# Výkony (5 řádků)
|
||||||
|
KOD_X = IL # x-start kódového rámečku
|
||||||
|
KOD_W = 108 # šířka kódového rámečku
|
||||||
|
KOD_H = 22 # výška kódového rámečku
|
||||||
|
TXT_X = KOD_X + KOD_W + 8 # x-start textové části
|
||||||
|
|
||||||
|
ROW_H = 42 # výška jednoho výkonu (rámeček + 2 řádky textu)
|
||||||
|
|
||||||
|
for vykon in (d.get("pozadovano", []) + [{}, {}, {}, {}, {}])[:5]:
|
||||||
|
y_top_row = yt(top)
|
||||||
|
|
||||||
|
# Kódový rámeček
|
||||||
|
c.setLineWidth(0.9)
|
||||||
|
c.setDash([])
|
||||||
|
c.rect(KOD_X, y_top_row - KOD_H - 4, KOD_W, KOD_H, stroke=1, fill=0)
|
||||||
|
# Hodnota kódu
|
||||||
|
kod_val = vykon.get("kod", "")
|
||||||
|
if kod_val:
|
||||||
|
txt(c, KOD_X + 5, y_top_row - KOD_H + 2, kod_val, size=9, bold=True)
|
||||||
|
|
||||||
|
# Textový řádek 1
|
||||||
|
txt(c, TXT_X, y_top_row - 10, vykon.get("popis", "")[:75], size=8)
|
||||||
|
dotline(c, TXT_X, y_top_row - 13, IR)
|
||||||
|
|
||||||
|
# Textový řádek 2 (pokračování)
|
||||||
|
txt(c, TXT_X, y_top_row - 25, vykon.get("popis2", "")[:75], size=8)
|
||||||
|
dotline(c, TXT_X, y_top_row - 28, IR)
|
||||||
|
|
||||||
|
top += ROW_H
|
||||||
|
|
||||||
|
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
# HLAVNÍ FUNKCE
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
def generuj_poukaz(data: dict, vystup: Path):
|
||||||
|
c = canvas.Canvas(str(vystup), pagesize=A4)
|
||||||
|
|
||||||
|
# Vnější zaoblený rámeček
|
||||||
|
c.setLineWidth(1.8)
|
||||||
|
c.roundRect(FX1, FB, FX2 - FX1, FT - FB, 6, stroke=1, fill=0)
|
||||||
|
|
||||||
|
draw_hlavicka(c, data)
|
||||||
|
draw_nadpis(c)
|
||||||
|
draw_pacient(c, data)
|
||||||
|
cur_top = draw_textova_pole(c, data)
|
||||||
|
draw_pozadovano(c, data, cur_top)
|
||||||
|
|
||||||
|
# Zápatí
|
||||||
|
txt(c, FX1 + 2, FB - 12, "VZP-06dp/2024", size=6)
|
||||||
|
|
||||||
|
c.save()
|
||||||
|
print(f"✓ Uloženo: {vystup}")
|
||||||
|
|
||||||
|
|
||||||
|
# ── Spuštění ──────────────────────────────────────────────────────────────────
|
||||||
|
if __name__ == "__main__":
|
||||||
|
folder = Path(__file__).parent
|
||||||
|
# Najde nejvyšší existující číslo verze a přidá 1
|
||||||
|
existing = [f for f in folder.glob("Poukaz DP vyplneny_v*.pdf")]
|
||||||
|
nums = []
|
||||||
|
for f in existing:
|
||||||
|
try:
|
||||||
|
nums.append(int(f.stem.rsplit("_v", 1)[1]))
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
pass
|
||||||
|
next_v = max(nums, default=2) + 1
|
||||||
|
out = folder / f"Poukaz DP vyplneny_v{next_v}.pdf"
|
||||||
|
generuj_poukaz(DATA, out)
|
||||||
|
dá 1
|
||||||
|
existing = [f for f in folder.glob("Poukaz DP vyplneny_v*.pdf")]
|
||||||
|
nums = []
|
||||||
|
for f in existing:
|
||||||
|
try:
|
||||||
|
nums.append(int(f.stem.rsplit("_v", 1)[1]))
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
pass
|
||||||
|
next_v = max(nums, default=2) + 1
|
||||||
|
out = folder / f"Poukaz DP vyplneny_v{next_v}.pdf"
|
||||||
|
generuj_poukaz(DATA, out)
|
||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user